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 
tls_prng_dev_open(const char * name,int timeout)88 TLS_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 
tls_prng_dev_read(TLS_PRNG_SRC * dev,size_t len)111 ssize_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     count = timed_read(dev->fd, buffer, rand_bytes, dev->timeout, (void *) 0);
127     if (count > 0) {
128 	if (msg_verbose)
129 	    msg_info("%s: read %ld bytes from entropy device %s",
130 		     myname, (long) count, dev->name);
131 	RAND_seed(buffer, count);
132     } else {
133 	if (msg_verbose)
134 	    msg_info("%s: cannot read %ld bytes from entropy device %s: %m",
135 		     myname, (long) rand_bytes, dev->name);
136     }
137     return (count);
138 }
139 
140 /* tls_prng_dev_close - disconnect from EGD server */
141 
tls_prng_dev_close(TLS_PRNG_SRC * dev)142 int     tls_prng_dev_close(TLS_PRNG_SRC *dev)
143 {
144     const char *myname = "tls_prng_dev_close";
145     int     err;
146 
147     if (msg_verbose)
148 	msg_info("%s: close entropy device %s", myname, dev->name);
149     err = close(dev->fd);
150     myfree(dev->name);
151     myfree((void *) dev);
152     return (err);
153 }
154 
155 #endif
156