xref: /netbsd-src/external/ibm-public/postfix/dist/src/tls/tls_prng_egd.c (revision e89934bbf778a6d6d6894877c4da59d0c7835b0f)
1 /*	$NetBSD: tls_prng_egd.c,v 1.2 2017/02/14 01:16:48 christos Exp $	*/
2 
3 /*++
4 /* NAME
5 /*	tls_prng_egd 3
6 /* SUMMARY
7 /*	seed OpenSSL PRNG from EGD server
8 /* SYNOPSIS
9 /*	#include <tls_prng_src.h>
10 /*
11 /*	TLS_PRNG_SRC *tls_prng_egd_open(name, timeout)
12 /*	const char *name;
13 /*	int	timeout;
14 /*
15 /*	ssize_t tls_prng_egd_read(egd, length)
16 /*	TLS_PRNG_SRC *egd;
17 /*	size_t length;
18 /*
19 /*	int	tls_prng_egd_close(egd)
20 /*	TLS_PRNG_SRC *egd;
21 /* DESCRIPTION
22 /*	tls_prng_egd_open() connect to the specified UNIX-domain service
23 /*	and returns a handle that should be used with all subsequent
24 /*	access.
25 /*
26 /*	tls_prng_egd_read() reads the requested number of bytes from
27 /*	the EGD server and updates the OpenSSL PRNG.
28 /*
29 /*	tls_prng_egd_close() disconnects from the specified EGD server
30 /*	and releases memory that was allocated for the handle.
31 /*
32 /*	Arguments:
33 /* .IP name
34 /*	The UNIX-domain pathname of the EGD service.
35 /* .IP length
36 /*	The number of bytes to read from the EGD server.
37 /*	Request lengths will be truncated at 255 bytes.
38 /* .IP timeout
39 /*	Time limit on individual I/O operations.
40 /* DIAGNOSTICS
41 /*	tls_prng_egd_open() returns a null pointer on error.
42 /*
43 /*	tls_prng_egd_read() returns -1 on error, the number
44 /*	of bytes received on success.
45 /*
46 /*	tls_prng_egd_close() returns -1 on error, 0 on success.
47 /*
48 /*	In all cases the errno variable indicates the type of error.
49 /* LICENSE
50 /* .ad
51 /* .fi
52 /*	The Secure Mailer license must be distributed with this software.
53 /* AUTHOR(S)
54 /*	Wietse Venema
55 /*	IBM T.J. Watson Research
56 /*	P.O. Box 704
57 /*	Yorktown Heights, NY 10598, USA
58 /*--*/
59 
60 /* System library. */
61 
62 #include <sys_defs.h>
63 #include <unistd.h>
64 #include <limits.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_egd_open - connect to EGD server */
87 
tls_prng_egd_open(const char * name,int timeout)88 TLS_PRNG_SRC *tls_prng_egd_open(const char *name, int timeout)
89 {
90     const char *myname = "tls_prng_egd_open";
91     TLS_PRNG_SRC *egd;
92     int     fd;
93 
94     if (msg_verbose)
95 	msg_info("%s: connect to EGD server %s", myname, name);
96 
97     if ((fd = unix_connect(name, BLOCKING, timeout)) < 0) {
98 	if (msg_verbose)
99 	    msg_info("%s: cannot connect to EGD server %s: %m", myname, name);
100 	return (0);
101     } else {
102 	egd = (TLS_PRNG_SRC *) mymalloc(sizeof(*egd));
103 	egd->fd = fd;
104 	egd->name = mystrdup(name);
105 	egd->timeout = timeout;
106 	if (msg_verbose)
107 	    msg_info("%s: connected to EGD server %s", myname, name);
108 	return (egd);
109     }
110 }
111 
112 /* tls_prng_egd_read - update internal PRNG from EGD server */
113 
tls_prng_egd_read(TLS_PRNG_SRC * egd,size_t len)114 ssize_t tls_prng_egd_read(TLS_PRNG_SRC *egd, size_t len)
115 {
116     const char *myname = "tls_prng_egd_read";
117     unsigned char buffer[UCHAR_MAX];
118     ssize_t count;
119 
120     if (len <= 0)
121 	msg_panic("%s: bad length %ld", myname, (long) len);
122 
123     buffer[0] = 1;
124     buffer[1] = (len > UCHAR_MAX ? UCHAR_MAX : len);
125 
126     if (timed_write(egd->fd, buffer, 2, egd->timeout, (void *) 0) != 2) {
127 	msg_info("cannot write to EGD server %s: %m", egd->name);
128 	return (-1);
129     }
130     if (timed_read(egd->fd, buffer, 1, egd->timeout, (void *) 0) != 1) {
131 	msg_info("cannot read from EGD server %s: %m", egd->name);
132 	return (-1);
133     }
134     count = buffer[0];
135     if (count > sizeof(buffer))
136 	count = sizeof(buffer);
137     if (count == 0) {
138 	msg_info("EGD server %s reports zero bytes available", egd->name);
139 	return (-1);
140     }
141     if (timed_read(egd->fd, buffer, count, egd->timeout, (void *) 0) != count) {
142 	msg_info("cannot read %ld bytes from EGD server %s: %m",
143 		 (long) count, egd->name);
144 	return (-1);
145     }
146     if (msg_verbose)
147 	msg_info("%s: got %ld bytes from EGD server %s", myname,
148 		 (long) count, egd->name);
149     RAND_seed(buffer, count);
150     return (count);
151 }
152 
153 /* tls_prng_egd_close - disconnect from EGD server */
154 
tls_prng_egd_close(TLS_PRNG_SRC * egd)155 int     tls_prng_egd_close(TLS_PRNG_SRC *egd)
156 {
157     const char *myname = "tls_prng_egd_close";
158     int     err;
159 
160     if (msg_verbose)
161 	msg_info("%s: close EGD server %s", myname, egd->name);
162     err = close(egd->fd);
163     myfree(egd->name);
164     myfree((void *) egd);
165     return (err);
166 }
167 
168 #endif
169