1/*++
2/* NAME
3/*	tls_prng_egd 3
4/* SUMMARY
5/*	seed OpenSSL PRNG from EGD server
6/* SYNOPSIS
7/*	#include <tls_prng_src.h>
8/*
9/*	TLS_PRNG_SRC *tls_prng_egd_open(name, timeout)
10/*	const char *name;
11/*	int	timeout;
12/*
13/*	ssize_t tls_prng_egd_read(egd, length)
14/*	TLS_PRNG_SRC *egd;
15/*	size_t length;
16/*
17/*	int	tls_prng_egd_close(egd)
18/*	TLS_PRNG_SRC *egd;
19/* DESCRIPTION
20/*	tls_prng_egd_open() connect to the specified UNIX-domain service
21/*	and returns a handle that should be used with all subsequent
22/*	access.
23/*
24/*	tls_prng_egd_read() reads the requested number of bytes from
25/*	the EGD server and updates the OpenSSL PRNG.
26/*
27/*	tls_prng_egd_close() disconnects from the specified EGD server
28/*	and releases memory that was allocated for the handle.
29/*
30/*	Arguments:
31/* .IP name
32/*	The UNIX-domain pathname of the EGD service.
33/* .IP length
34/*	The number of bytes to read from the EGD server.
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_egd_open() returns a null pointer on error.
40/*
41/*	tls_prng_egd_read() returns -1 on error, the number
42/*	of bytes received on success.
43/*
44/*	tls_prng_egd_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 <unistd.h>
62#include <limits.h>
63
64#ifndef UCHAR_MAX
65#define UCHAR_MAX 0xff
66#endif
67
68/* OpenSSL library. */
69
70#ifdef USE_TLS
71#include <openssl/rand.h>		/* For the PRNG */
72
73/* Utility library. */
74
75#include <msg.h>
76#include <mymalloc.h>
77#include <connect.h>
78#include <iostuff.h>
79
80/* TLS library. */
81
82#include <tls_prng.h>
83
84/* tls_prng_egd_open - connect to EGD server */
85
86TLS_PRNG_SRC *tls_prng_egd_open(const char *name, int timeout)
87{
88    const char *myname = "tls_prng_egd_open";
89    TLS_PRNG_SRC *egd;
90    int     fd;
91
92    if (msg_verbose)
93	msg_info("%s: connect to EGD server %s", myname, name);
94
95    if ((fd = unix_connect(name, BLOCKING, timeout)) < 0) {
96	if (msg_verbose)
97	    msg_info("%s: cannot connect to EGD server %s: %m", myname, name);
98	return (0);
99    } else {
100	egd = (TLS_PRNG_SRC *) mymalloc(sizeof(*egd));
101	egd->fd = fd;
102	egd->name = mystrdup(name);
103	egd->timeout = timeout;
104	if (msg_verbose)
105	    msg_info("%s: connected to EGD server %s", myname, name);
106	return (egd);
107    }
108}
109
110/* tls_prng_egd_read - update internal PRNG from EGD server */
111
112ssize_t tls_prng_egd_read(TLS_PRNG_SRC *egd, size_t len)
113{
114    const char *myname = "tls_prng_egd_read";
115    unsigned char buffer[UCHAR_MAX];
116    ssize_t count;
117
118    if (len <= 0)
119	msg_panic("%s: bad length %ld", myname, (long) len);
120
121    buffer[0] = 1;
122    buffer[1] = (len > UCHAR_MAX ? UCHAR_MAX : len);
123
124    if (timed_write(egd->fd, buffer, 2, egd->timeout, (void *) 0) != 2) {
125	msg_info("cannot write to EGD server %s: %m", egd->name);
126	return (-1);
127    }
128    if (timed_read(egd->fd, buffer, 1, egd->timeout, (void *) 0) != 1) {
129	msg_info("cannot read from EGD server %s: %m", egd->name);
130	return (-1);
131    }
132    count = buffer[0];
133    if (count > sizeof(buffer))
134	count = sizeof(buffer);
135    if (count == 0) {
136	msg_info("EGD server %s reports zero bytes available", egd->name);
137	return (-1);
138    }
139    if (timed_read(egd->fd, buffer, count, egd->timeout, (void *) 0) != count) {
140	msg_info("cannot read %ld bytes from EGD server %s: %m",
141		 (long) count, egd->name);
142	return (-1);
143    }
144    if (msg_verbose)
145	msg_info("%s: got %ld bytes from EGD server %s", myname,
146		 (long) count, egd->name);
147    RAND_seed(buffer, count);
148    return (count);
149}
150
151/* tls_prng_egd_close - disconnect from EGD server */
152
153int     tls_prng_egd_close(TLS_PRNG_SRC *egd)
154{
155    const char *myname = "tls_prng_egd_close";
156    int     err;
157
158    if (msg_verbose)
159	msg_info("%s: close EGD server %s", myname, egd->name);
160    err = close(egd->fd);
161    myfree(egd->name);
162    myfree((char *) egd);
163    return (err);
164}
165
166#endif
167