1:
2: /*
3: * Copyright (c) 2001-2002 Packet Design, LLC.
4: * All rights reserved.
5: *
6: * Subject to the following obligations and disclaimer of warranty,
7: * use and redistribution of this software, in source or object code
8: * forms, with or without modifications are expressly permitted by
9: * Packet Design; provided, however, that:
10: *
11: * (i) Any and all reproductions of the source or object code
12: * must include the copyright notice above and the following
13: * disclaimer of warranties; and
14: * (ii) No rights are granted, in any manner or form, to use
15: * Packet Design trademarks, including the mark "PACKET DESIGN"
16: * on advertising, endorsements, or otherwise except as such
17: * appears in the above copyright notice or in the software.
18: *
19: * THIS SOFTWARE IS BEING PROVIDED BY PACKET DESIGN "AS IS", AND
20: * TO THE MAXIMUM EXTENT PERMITTED BY LAW, PACKET DESIGN MAKES NO
21: * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING
22: * THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED
23: * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
24: * OR NON-INFRINGEMENT. PACKET DESIGN DOES NOT WARRANT, GUARANTEE,
25: * OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS
26: * OF THE USE OF THIS SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY,
27: * RELIABILITY OR OTHERWISE. IN NO EVENT SHALL PACKET DESIGN BE
28: * LIABLE FOR ANY DAMAGES RESULTING FROM OR ARISING OUT OF ANY USE
29: * OF THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY DIRECT,
30: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE, OR CONSEQUENTIAL
31: * DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF
32: * USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY THEORY OF
33: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
35: * THE USE OF THIS SOFTWARE, EVEN IF PACKET DESIGN IS ADVISED OF
36: * THE POSSIBILITY OF SUCH DAMAGE.
37: *
38: * Author: Archie Cobbs <archie@freebsd.org>
39: */
40:
41: #include <sys/param.h>
42: #include <sys/syslog.h>
43:
44: #include <stdio.h>
45: #include <stdlib.h>
46: #include <stdarg.h>
47: #include <string.h>
48: #include <unistd.h>
49: #include <fcntl.h>
50: #include <errno.h>
51: #include <poll.h>
52: #include <pthread.h>
53:
54: #include <openssl/ssl.h>
55: #include <openssl/err.h>
56:
57: #include "structs/structs.h"
58: #include "structs/type/array.h"
59:
60: #include "util/typed_mem.h"
61: #include "io/ssl_fp.h"
62:
63: struct ssl_info {
64: int fd;
65: SSL *ssl;
66: SSL_CTX *ssl_ctx;
67: int error;
68: u_char server;
69: ssl_logger_t *logger;
70: void *logarg;
71: const char *mtype;
72: u_int timeout;
73: };
74:
75: /*
76: * Internal functions
77: */
78: static int ssl_read(void *cookie, char *buf, int len);
79: static int ssl_write(void *cookie, const char *buf, int len);
80: static int ssl_close(void *cookie);
81: static int ssl_check(struct ssl_info *s);
82: static int ssl_err(struct ssl_info *s, int ret);
83:
84: static ssl_logger_t null_logger;
85:
86: /*
87: * Create a FILE * from an SSL connection.
88: */
89: FILE *
90: ssl_fdopen(SSL_CTX *ssl_ctx, int fd, int server, const char *mtype,
91: ssl_logger_t *logger, void *logarg, u_int timeout)
92: {
93: struct ssl_info *s;
94: int flags;
95: FILE *fp;
96:
97: /* Create SSL info */
98: if ((s = MALLOC(mtype, sizeof(*s))) == NULL)
99: return (NULL);
100: memset(s, 0, sizeof(*s));
101: s->fd = fd;
102: s->ssl_ctx = ssl_ctx;
103: s->mtype = mtype;
104: s->server = !!server;
105: s->logger = (logger != NULL) ? logger : null_logger;
106: s->logarg = logarg;
107: s->timeout = timeout;
108:
109: /* Set fd I/O to non-blocking */
110: if ((flags = fcntl(fd, F_GETFL, 0)) == -1) {
111: FREE(mtype, s);
112: return (NULL);
113: }
114: #if 0
115: if ((flags & O_NONBLOCK) == 0
116: && fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
117: FREE(mtype, s);
118: return (NULL);
119: }
120: #endif
121:
122: /* Create FILE * stream */
123: if ((fp = funopen(s, ssl_read, ssl_write, NULL, ssl_close)) == NULL) {
124: (void)fcntl(fd, F_SETFL, flags);
125: FREE(mtype, s);
126: return (NULL);
127: }
128:
129: /* Done */
130: return (fp);
131: }
132:
133: /*
134: * Read from an SSL connection.
135: */
136: static int
137: ssl_read(void *cookie, char *buf, int len)
138: {
139: struct ssl_info *const s = cookie;
140: int ret;
141:
142: /* Check connection */
143: if (ssl_check(s) == -1)
144: return (-1);
145:
146: tryread:
147: /* Try to read some more data */
148: if ((ret = SSL_read(s->ssl, buf, len)) <= 0) {
149: if (ssl_err(s, ret) == -1)
150: return (-1);
151: goto tryread;
152: }
153: return (ret);
154: }
155:
156: /*
157: * Write to an SSL connection.
158: */
159: static int
160: ssl_write(void *cookie, const char *buf, int len)
161: {
162: struct ssl_info *const s = cookie;
163: int ret;
164:
165: /* Check connection */
166: if (ssl_check(s) == -1)
167: return (-1);
168:
169: trywrite:
170: /* Try to write some more data */
171: if ((ret = SSL_write(s->ssl, buf, len)) <= 0) {
172: if (ssl_err(s, ret) == -1)
173: return (-1);
174: goto trywrite;
175: }
176: return (ret);
177: }
178:
179: /*
180: * Close an SSL connection.
181: */
182: static int
183: ssl_close(void *cookie)
184: {
185: struct ssl_info *const s = cookie;
186: int ret;
187:
188: while ((ret = SSL_shutdown(s->ssl)) <= 0) {
189: if (ret == -1 && ssl_err(s, ret) == -1) {
190: (void)close(s->fd);
191: return (-1);
192: }
193: }
194: (void)close(s->fd);
195: SSL_free(s->ssl);
196: FREE(s->mtype, s);
197: return (0);
198: }
199:
200: /*
201: * Check SSL connection context.
202: */
203: static int
204: ssl_check(struct ssl_info *s)
205: {
206: int ret;
207:
208: /* Check for previous error */
209: if (s->error != 0)
210: goto fail;
211:
212: /* Already set up SSL? */
213: if (s->ssl != NULL)
214: return (0);
215:
216: /* Create ssl connection context */
217: if ((s->ssl = SSL_new(s->ssl_ctx)) == NULL) {
218: ssl_log(s->logger, s->logarg);
219: s->error = ECONNABORTED;
220: goto fail;
221: }
222: SSL_set_fd(s->ssl, s->fd);
223:
224: /* Do initial SSL handshake */
225: if (s->server) {
226: while ((ret = SSL_accept(s->ssl)) <= 0) {
227: if (ssl_err(s, ret) == -1)
228: goto fail;
229: }
230: } else {
231: while ((ret = SSL_connect(s->ssl)) <= 0) {
232: if (ssl_err(s, ret) == -1)
233: goto fail;
234: }
235: }
236:
237: /* Ready */
238: return (0);
239:
240: fail:
241: /* Failed */
242: errno = s->error;
243: return (-1);
244: }
245:
246: /*
247: * Handle an error return from an SSL I/O operation.
248: *
249: * It might be an error, or it might just be that more raw data
250: * needs to be read or written. Return -1 in the former case,
251: * otherwise return zero and wait for the readable or writable
252: * event as appropriate.
253: */
254: static int
255: ssl_err(struct ssl_info *s, int ret)
256: {
257: int ret2;
258:
259: ret2 = SSL_get_error(s->ssl, ret);
260: switch (ret2) {
261: case SSL_ERROR_WANT_READ:
262: case SSL_ERROR_WANT_WRITE:
263: {
264: struct pollfd pfd;
265: int timeout;
266: int nfds;
267:
268: /* Set up read/write poll(2) event */
269: memset(&pfd, 0, sizeof(pfd));
270: pfd.fd = s->fd;
271: pfd.events = (ret2 == SSL_ERROR_WANT_READ) ?
272: POLLRDNORM : POLLWRNORM;
273:
274: /* Set up timeout */
275: timeout = INFTIM;
276: if (s->timeout != 0)
277: timeout = s->timeout * 1000;
278:
279: /* Wait for readability or writability */
280: if ((nfds = poll(&pfd, 1, timeout)) == -1) {
281: s->error = errno;
282: (*s->logger)(s->logarg, LOG_ERR,
283: "%s: %s", "poll", strerror(errno));
284: goto fail;
285: }
286:
287: /* Check for timeout */
288: if (nfds == 0) {
289: s->error = ETIMEDOUT;
290: goto fail;
291: }
292:
293: /* Done */
294: return (0);
295: }
296: case SSL_ERROR_NONE:
297: return (0);
298:
299: case SSL_ERROR_SYSCALL:
300: ssl_log(s->logger, s->logarg);
301: if (ret != 0) {
302: s->error = errno;
303: (*s->logger)(s->logarg, LOG_ERR,
304: "SSL system error: %s", strerror(errno));
305: goto fail;
306: }
307: /* fall through */
308:
309: case SSL_ERROR_ZERO_RETURN:
310: (*s->logger)(s->logarg, LOG_ERR, "SSL connection closed");
311: s->error = ECONNRESET;
312: goto fail;
313:
314: case SSL_ERROR_SSL:
315: ssl_log(s->logger, s->logarg);
316: s->error = EIO;
317: goto fail;
318:
319: case SSL_ERROR_WANT_X509_LOOKUP: /* should not happen */
320: default:
321: ssl_log(s->logger, s->logarg);
322: (*s->logger)(s->logarg, LOG_ERR,
323: "unknown return %d from SSL_get_error", ret2);
324: s->error = ECONNABORTED;
325: goto fail;
326: }
327:
328: fail:
329: /* Got an error */
330: errno = s->error;
331: return (-1);
332: }
333:
334: /*
335: * Log an SSL error.
336: */
337: void
338: ssl_log(ssl_logger_t *logger, void *logarg)
339: {
340: char buf[200];
341: const char *file;
342: const char *str;
343: const char *t;
344: int line, flags;
345: u_long e;
346:
347: while ((e = ERR_get_error_line_data(&file, &line, &str, &flags)) != 0) {
348: if (logger == NULL)
349: continue;
350: #if 0
351: (*logger)(logarg, LOG_ERR, "SSL: %s:%s:%d:%s\n",
352: ERR_error_string(e, buf), file, line,
353: (flags & ERR_TXT_STRING) ? str : "");
354: #else
355: strlcpy(buf, "SSL: ", sizeof(buf));
356: #if 0
357: /* Add library */
358: if ((t = ERR_lib_error_string(e)) != NULL) {
359: strlcat(buf, t, sizeof(buf));
360: strlcat(buf, ": ", sizeof(buf));
361: } else {
362: snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
363: "lib=%u: ", ERR_GET_LIB(e));
364: }
365: #endif
366:
367: /* Add function */
368: if ((t = ERR_func_error_string(e)) != NULL) {
369: strlcat(buf, t, sizeof(buf));
370: strlcat(buf, ": ", sizeof(buf));
371: } else {
372: snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
373: "func=%u: ", ERR_GET_FUNC(e));
374: }
375:
376: /* Add reason */
377: if ((t = ERR_reason_error_string(e)) != NULL) {
378: strlcat(buf, t, sizeof(buf));
379: } else {
380: snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
381: "reason=%u", ERR_GET_REASON(e));
382: }
383:
384: /* Add error text, if any */
385: if ((flags & ERR_TXT_STRING) != 0) {
386: strlcat(buf, ": ", sizeof(buf));
387: strlcat(buf, str, sizeof(buf));
388: }
389: (*logger)(logarg, LOG_ERR, "%s", buf);
390: #endif
391: }
392: }
393:
394: static void
395: null_logger(void *arg, int sev, const char *fmt, ...)
396: {
397: return;
398: }
399:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>