1 /* $NetBSD: tls_bio_ops.c,v 1.1.1.6 2020/05/25 23:40:34 christos Exp $ */
2
3 /*++
4 /* NAME
5 /* tls_bio_ops 3
6 /* SUMMARY
7 /* TLS network basic I/O management
8 /* SYNOPSIS
9 /* #define TLS_INTERNAL
10 /* #include <tls.h>
11 /*
12 /* int tls_bio_connect(fd, timeout, context)
13 /* int fd;
14 /* int timeout;
15 /* TLS_SESS_STATE *context;
16 /*
17 /* int tls_bio_accept(fd, timeout, context)
18 /* int fd;
19 /* int timeout;
20 /* TLS_SESS_STATE *context;
21 /*
22 /* int tls_bio_shutdown(fd, timeout, context)
23 /* int fd;
24 /* int timeout;
25 /* TLS_SESS_STATE *context;
26 /*
27 /* int tls_bio_read(fd, buf, len, timeout, context)
28 /* int fd;
29 /* void *buf;
30 /* int len;
31 /* int timeout;
32 /* TLS_SESS_STATE *context;
33 /*
34 /* int tls_bio_write(fd, buf, len, timeout, context)
35 /* int fd;
36 /* void *buf;
37 /* int len;
38 /* int timeout;
39 /* TLS_SESS_STATE *context;
40 /* DESCRIPTION
41 /* This module enforces VSTREAM-style timeouts on non-blocking
42 /* I/O while performing TLS handshake or input/output operations.
43 /*
44 /* The Postfix VSTREAM read/write routines invoke the
45 /* tls_bio_read/write routines to send and receive plain-text
46 /* data. In addition, this module provides tls_bio_connect/accept
47 /* routines that trigger the initial TLS handshake. The
48 /* tls_bio_xxx routines invoke the corresponding SSL routines
49 /* that translate the requests into TLS protocol messages.
50 /*
51 /* Whenever an SSL operation indicates that network input (or
52 /* output) needs to happen, the tls_bio_xxx routines wait for
53 /* the network to become readable (or writable) within the
54 /* timeout limit, then retry the SSL operation. This works
55 /* because the network socket is in non-blocking mode.
56 /*
57 /* tls_bio_connect() performs the SSL_connect() operation.
58 /*
59 /* tls_bio_accept() performs the SSL_accept() operation.
60 /*
61 /* tls_bio_shutdown() performs the SSL_shutdown() operation.
62 /*
63 /* tls_bio_read() performs the SSL_read() operation.
64 /*
65 /* tls_bio_write() performs the SSL_write() operation.
66 /*
67 /* Arguments:
68 /* .IP fd
69 /* Network socket.
70 /* .IP buf
71 /* Read/write buffer.
72 /* .IP len
73 /* Read/write request size.
74 /* .IP timeout
75 /* Read/write timeout.
76 /* .IP TLScontext
77 /* TLS session state.
78 /* DIAGNOSTICS
79 /* A result value > 0 means successful completion.
80 /*
81 /* A result value < 0 means that the requested operation did
82 /* not complete due to TLS protocol failure, system call
83 /* failure, or for any reason described under "in addition"
84 /* below.
85 /*
86 /* A result value of 0 from tls_bio_shutdown() means that the
87 /* operation is in progress. A result value of 0 from other
88 /* tls_bio_ops(3) operations means that the remote party either
89 /* closed the network connection or that it sent a TLS shutdown
90 /* request.
91 /*
92 /* Upon return from the tls_bio_ops(3) routines the global
93 /* errno value is non-zero when the requested operation did not
94 /* complete due to system call failure.
95 /*
96 /* In addition, the result value is set to -1, and the global
97 /* errno value is set to ETIMEDOUT, when some network read/write
98 /* operation did not complete within the time limit.
99 /* LICENSE
100 /* .ad
101 /* .fi
102 /* This software is free. You can do with it whatever you want.
103 /* The original author kindly requests that you acknowledge
104 /* the use of his software.
105 /* AUTHOR(S)
106 /* Originally written by:
107 /* Lutz Jaenicke
108 /* BTU Cottbus
109 /* Allgemeine Elektrotechnik
110 /* Universitaetsplatz 3-4
111 /* D-03044 Cottbus, Germany
112 /*
113 /* Updated by:
114 /* Wietse Venema
115 /* IBM T.J. Watson Research
116 /* P.O. Box 704
117 /* Yorktown Heights, NY 10598, USA
118 /*
119 /* Victor Duchovni
120 /* Morgan Stanley
121 /*--*/
122
123 /* System library. */
124
125 #include <sys_defs.h>
126 #include <sys/time.h>
127
128 #ifndef timersub
129 /* res = a - b */
130 #define timersub(a, b, res) do { \
131 (res)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
132 (res)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
133 if ((res)->tv_usec < 0) { \
134 (res)->tv_sec--; \
135 (res)->tv_usec += 1000000; \
136 } \
137 } while (0)
138 #endif
139
140 #ifdef USE_TLS
141
142 /* Utility library. */
143
144 #include <msg.h>
145 #include <iostuff.h>
146
147 /* TLS library. */
148
149 #define TLS_INTERNAL
150 #include <tls.h>
151
152 /* tls_bio - perform SSL input/output operation with extreme prejudice */
153
tls_bio(int fd,int timeout,TLS_SESS_STATE * TLScontext,int (* hsfunc)(SSL *),int (* rfunc)(SSL *,void *,int),int (* wfunc)(SSL *,const void *,int),void * buf,int num)154 int tls_bio(int fd, int timeout, TLS_SESS_STATE *TLScontext,
155 int (*hsfunc) (SSL *),
156 int (*rfunc) (SSL *, void *, int),
157 int (*wfunc) (SSL *, const void *, int),
158 void *buf, int num)
159 {
160 const char *myname = "tls_bio";
161 int status;
162 int err;
163 int enable_deadline;
164 struct timeval time_left; /* amount of time left */
165 struct timeval time_deadline; /* time of deadline */
166 struct timeval time_now; /* time after SSL_mumble() call */
167
168 /*
169 * Compensation for interface mis-match: With VSTREAMs, timeout <= 0
170 * means wait forever; with the read/write_wait() calls below, we need to
171 * specify timeout < 0 instead.
172 *
173 * Safety: no time limit means no deadline.
174 */
175 if (timeout <= 0) {
176 timeout = -1;
177 enable_deadline = 0;
178 }
179
180 /*
181 * Deadline management is simpler than with VSTREAMs, because we don't
182 * need to decrement a per-stream time limit. We just work within the
183 * budget that is available for this tls_bio() call.
184 */
185 else {
186 enable_deadline =
187 vstream_fstat(TLScontext->stream, VSTREAM_FLAG_DEADLINE);
188 if (enable_deadline) {
189 GETTIMEOFDAY(&time_deadline);
190 time_deadline.tv_sec += timeout;
191 }
192 }
193
194 /*
195 * If necessary, retry the SSL handshake or read/write operation after
196 * handling any pending network I/O.
197 */
198 for (;;) {
199
200 /*
201 * Flush the per-thread SSL error queue. Otherwise, errors from other
202 * code that also uses TLS may confuse SSL_get_error(3).
203 */
204 ERR_clear_error();
205
206 if (hsfunc)
207 status = hsfunc(TLScontext->con);
208 else if (rfunc)
209 status = rfunc(TLScontext->con, buf, num);
210 else if (wfunc)
211 status = wfunc(TLScontext->con, buf, num);
212 else
213 msg_panic("%s: nothing to do here", myname);
214 err = SSL_get_error(TLScontext->con, status);
215
216 /*
217 * Correspondence between SSL_ERROR_* error codes and tls_bio_(read,
218 * write, accept, connect, shutdown) return values (for brevity:
219 * retval).
220 *
221 * SSL_ERROR_NONE corresponds with retval > 0. With SSL_(read, write)
222 * this is the number of plaintext bytes sent or received. With
223 * SSL_(accept, connect, shutdown) this means that the operation was
224 * completed successfully.
225 *
226 * SSL_ERROR_WANT_(WRITE, READ) start a new loop iteration, or force
227 * (retval = -1, errno = ETIMEDOUT) when the time limit is exceeded.
228 *
229 * All other SSL_ERROR_* cases correspond with retval <= 0. With
230 * SSL_(read, write, accept, connect) retval == 0 means that the
231 * remote party either closed the network connection or that it
232 * requested TLS shutdown; with SSL_shutdown() retval == 0 means that
233 * our own shutdown request is in progress. With all operations
234 * retval < 0 means that there was an error. In the latter case,
235 * SSL_ERROR_SYSCALL means that error details are returned via the
236 * errno value.
237 *
238 * Find out if we must retry the operation and/or if there is pending
239 * network I/O.
240 *
241 * XXX If we're the first to invoke SSL_shutdown(), then the operation
242 * isn't really complete when the call returns. We could hide that
243 * anomaly here and repeat the call.
244 */
245 switch (err) {
246 case SSL_ERROR_WANT_WRITE:
247 case SSL_ERROR_WANT_READ:
248 if (enable_deadline) {
249 GETTIMEOFDAY(&time_now);
250 timersub(&time_deadline, &time_now, &time_left);
251 timeout = time_left.tv_sec + (time_left.tv_usec > 0);
252 if (timeout <= 0) {
253 errno = ETIMEDOUT;
254 return (-1);
255 }
256 }
257 if (err == SSL_ERROR_WANT_WRITE) {
258 if (write_wait(fd, timeout) < 0)
259 return (-1); /* timeout error */
260 } else {
261 if (read_wait(fd, timeout) < 0)
262 return (-1); /* timeout error */
263 }
264 break;
265
266 /*
267 * Unhandled cases: SSL_ERROR_WANT_(ACCEPT, CONNECT, X509_LOOKUP)
268 * etc. Historically, Postfix silently treated these as ordinary
269 * I/O errors so we don't really know how common they are. For
270 * now, we just log a warning.
271 */
272 default:
273 msg_warn("%s: unexpected SSL_ERROR code %d", myname, err);
274 /* FALLTHROUGH */
275
276 /*
277 * With tls_timed_read() and tls_timed_write() the caller is the
278 * VSTREAM library module which is unaware of TLS, so we log the
279 * TLS error stack here. In a better world, each VSTREAM I/O
280 * object would provide an error reporting method in addition to
281 * the timed_read and timed_write methods, so that we would not
282 * need to have ad-hoc code like this.
283 */
284 case SSL_ERROR_SSL:
285 if (rfunc || wfunc)
286 tls_print_errors();
287 /* FALLTHROUGH */
288 case SSL_ERROR_ZERO_RETURN:
289 case SSL_ERROR_NONE:
290 errno = 0; /* avoid bogus warnings */
291 /* FALLTHROUGH */
292 case SSL_ERROR_SYSCALL:
293 return (status);
294 }
295 }
296 }
297
298 #endif
299