ssl.c revision 1.7 1 /* $NetBSD: ssl.c,v 1.7 2019/04/04 00:36:09 christos Exp $ */
2
3 /*-
4 * Copyright (c) 1998-2004 Dag-Erling Codan Smrgrav
5 * Copyright (c) 2008, 2010 Joerg Sonnenberger <joerg (at) NetBSD.org>
6 * Copyright (c) 2015 Thomas Klausner <wiz (at) NetBSD.org>
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer
14 * in this position and unchanged.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 * $FreeBSD: common.c,v 1.53 2007/12/19 00:26:36 des Exp $
33 */
34
35 #include <sys/cdefs.h>
36 #ifndef lint
37 __RCSID("$NetBSD: ssl.c,v 1.7 2019/04/04 00:36:09 christos Exp $");
38 #endif
39
40 #include <time.h>
41 #include <unistd.h>
42 #include <string.h>
43 #include <fcntl.h>
44
45 #include <sys/param.h>
46 #include <sys/select.h>
47 #include <sys/uio.h>
48
49 #include <netinet/tcp.h>
50 #include <netinet/in.h>
51 #include <openssl/crypto.h>
52 #include <openssl/x509.h>
53 #include <openssl/pem.h>
54 #include <openssl/ssl.h>
55 #include <openssl/err.h>
56
57 #include "ssl.h"
58
59 extern int quit_time, verbose, ftp_debug;
60 extern FILE *ttyout;
61
62 struct fetch_connect {
63 int sd; /* file/socket descriptor */
64 char *buf; /* buffer */
65 size_t bufsize; /* buffer size */
66 size_t bufpos; /* position of buffer */
67 size_t buflen; /* length of buffer contents */
68 struct { /* data cached after an
69 interrupted read */
70 char *buf;
71 size_t size;
72 size_t pos;
73 size_t len;
74 } cache;
75 int issock;
76 int iserr;
77 int iseof;
78 SSL *ssl; /* SSL handle */
79 };
80
81 /*
82 * Write a vector to a connection w/ timeout
83 * Note: can modify the iovec.
84 */
85 static ssize_t
86 fetch_writev(struct fetch_connect *conn, struct iovec *iov, int iovcnt)
87 {
88 struct timeval now, timeout, delta;
89 fd_set writefds;
90 ssize_t len, total;
91 int r;
92
93 if (quit_time > 0) {
94 FD_ZERO(&writefds);
95 gettimeofday(&timeout, NULL);
96 timeout.tv_sec += quit_time;
97 }
98
99 total = 0;
100 while (iovcnt > 0) {
101 while (quit_time > 0 && !FD_ISSET(conn->sd, &writefds)) {
102 FD_SET(conn->sd, &writefds);
103 gettimeofday(&now, NULL);
104 delta.tv_sec = timeout.tv_sec - now.tv_sec;
105 delta.tv_usec = timeout.tv_usec - now.tv_usec;
106 if (delta.tv_usec < 0) {
107 delta.tv_usec += 1000000;
108 delta.tv_sec--;
109 }
110 if (delta.tv_sec < 0) {
111 errno = ETIMEDOUT;
112 return -1;
113 }
114 errno = 0;
115 r = select(conn->sd + 1, NULL, &writefds, NULL, &delta);
116 if (r == -1) {
117 if (errno == EINTR)
118 continue;
119 return -1;
120 }
121 }
122 errno = 0;
123 if (conn->ssl != NULL)
124 len = SSL_write(conn->ssl, iov->iov_base, iov->iov_len);
125 else
126 len = writev(conn->sd, iov, iovcnt);
127 if (len == 0) {
128 /* we consider a short write a failure */
129 /* XXX perhaps we shouldn't in the SSL case */
130 errno = EPIPE;
131 return -1;
132 }
133 if (len < 0) {
134 if (errno == EINTR)
135 continue;
136 return -1;
137 }
138 total += len;
139 while (iovcnt > 0 && len >= (ssize_t)iov->iov_len) {
140 len -= iov->iov_len;
141 iov++;
142 iovcnt--;
143 }
144 if (iovcnt > 0) {
145 iov->iov_len -= len;
146 iov->iov_base = (char *)iov->iov_base + len;
147 }
148 }
149 return total;
150 }
151
152 /*
153 * Write to a connection w/ timeout
154 */
155 static int
156 fetch_write(struct fetch_connect *conn, const char *str, size_t len)
157 {
158 struct iovec iov[1];
159
160 iov[0].iov_base = (char *)__UNCONST(str);
161 iov[0].iov_len = len;
162 return fetch_writev(conn, iov, 1);
163 }
164
165 /*
166 * Send a formatted line; optionally echo to terminal
167 */
168 int
169 fetch_printf(struct fetch_connect *conn, const char *fmt, ...)
170 {
171 va_list ap;
172 size_t len;
173 char *msg;
174 int r;
175
176 va_start(ap, fmt);
177 len = vasprintf(&msg, fmt, ap);
178 va_end(ap);
179
180 if (msg == NULL) {
181 errno = ENOMEM;
182 return -1;
183 }
184
185 r = fetch_write(conn, msg, len);
186 free(msg);
187 return r;
188 }
189
190 int
191 fetch_fileno(struct fetch_connect *conn)
192 {
193
194 return conn->sd;
195 }
196
197 int
198 fetch_error(struct fetch_connect *conn)
199 {
200
201 return conn->iserr;
202 }
203
204 static void
205 fetch_clearerr(struct fetch_connect *conn)
206 {
207
208 conn->iserr = 0;
209 }
210
211 int
212 fetch_flush(struct fetch_connect *conn)
213 {
214 int v;
215
216 if (conn->issock) {
217 #ifdef TCP_NOPUSH
218 v = 0;
219 setsockopt(conn->sd, IPPROTO_TCP, TCP_NOPUSH, &v, sizeof(v));
220 #endif
221 v = 1;
222 setsockopt(conn->sd, IPPROTO_TCP, TCP_NODELAY, &v, sizeof(v));
223 }
224 return 0;
225 }
226
227 /*ARGSUSED*/
228 struct fetch_connect *
229 fetch_open(const char *fname, const char *fmode)
230 {
231 struct fetch_connect *conn;
232 int fd;
233
234 fd = open(fname, O_RDONLY); /* XXX: fmode */
235 if (fd < 0)
236 return NULL;
237
238 if ((conn = calloc(1, sizeof(*conn))) == NULL) {
239 close(fd);
240 return NULL;
241 }
242
243 conn->sd = fd;
244 conn->issock = 0;
245 return conn;
246 }
247
248 /*ARGSUSED*/
249 struct fetch_connect *
250 fetch_fdopen(int sd, const char *fmode)
251 {
252 struct fetch_connect *conn;
253 #if defined(SO_NOSIGPIPE) || defined(TCP_NOPUSH)
254 int opt = 1;
255 #endif
256
257 if ((conn = calloc(1, sizeof(*conn))) == NULL)
258 return NULL;
259
260 conn->sd = sd;
261 conn->issock = 1;
262 fcntl(sd, F_SETFD, FD_CLOEXEC);
263 #ifdef SO_NOSIGPIPE
264 setsockopt(sd, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof(opt));
265 #endif
266 #ifdef TCP_NOPUSH
267 setsockopt(sd, IPPROTO_TCP, TCP_NOPUSH, &opt, sizeof(opt));
268 #endif
269 return conn;
270 }
271
272 int
273 fetch_close(struct fetch_connect *conn)
274 {
275 int rv = 0;
276
277 if (conn != NULL) {
278 fetch_flush(conn);
279 SSL_free(conn->ssl);
280 rv = close(conn->sd);
281 if (rv < 0) {
282 errno = rv;
283 rv = EOF;
284 }
285 free(conn->cache.buf);
286 free(conn->buf);
287 free(conn);
288 }
289 return rv;
290 }
291
292 #define FETCH_READ_WAIT -2
293 #define FETCH_READ_ERROR -1
294
295 static ssize_t
296 fetch_ssl_read(SSL *ssl, void *buf, size_t len)
297 {
298 ssize_t rlen;
299 int ssl_err;
300
301 rlen = SSL_read(ssl, buf, len);
302 if (rlen < 0) {
303 ssl_err = SSL_get_error(ssl, rlen);
304 if (ssl_err == SSL_ERROR_WANT_READ ||
305 ssl_err == SSL_ERROR_WANT_WRITE) {
306 return FETCH_READ_WAIT;
307 }
308 ERR_print_errors_fp(ttyout);
309 return FETCH_READ_ERROR;
310 }
311 return rlen;
312 }
313
314 static ssize_t
315 fetch_nonssl_read(int sd, void *buf, size_t len)
316 {
317 ssize_t rlen;
318
319 rlen = read(sd, buf, len);
320 if (rlen < 0) {
321 if (errno == EAGAIN || errno == EINTR)
322 return FETCH_READ_WAIT;
323 return FETCH_READ_ERROR;
324 }
325 return rlen;
326 }
327
328 /*
329 * Cache some data that was read from a socket but cannot be immediately
330 * returned because of an interrupted system call.
331 */
332 static int
333 fetch_cache_data(struct fetch_connect *conn, char *src, size_t nbytes)
334 {
335
336 if (conn->cache.size < nbytes) {
337 char *tmp = realloc(conn->cache.buf, nbytes);
338 if (tmp == NULL)
339 return -1;
340
341 conn->cache.buf = tmp;
342 conn->cache.size = nbytes;
343 }
344
345 memcpy(conn->cache.buf, src, nbytes);
346 conn->cache.len = nbytes;
347 conn->cache.pos = 0;
348 return 0;
349 }
350
351 size_t
352 fetch_read(void *ptr, size_t size, size_t nmemb, struct fetch_connect *conn)
353 {
354 struct timeval now, timeout, delta;
355 fd_set readfds;
356 ssize_t rlen, total;
357 size_t len;
358 char *start, *buf;
359
360 if (quit_time > 0) {
361 gettimeofday(&timeout, NULL);
362 timeout.tv_sec += quit_time;
363 }
364
365 total = 0;
366 start = buf = ptr;
367 len = size * nmemb;
368
369 if (conn->cache.len > 0) {
370 /*
371 * The last invocation of fetch_read was interrupted by a
372 * signal after some data had been read from the socket. Copy
373 * the cached data into the supplied buffer before trying to
374 * read from the socket again.
375 */
376 total = (conn->cache.len < len) ? conn->cache.len : len;
377 memcpy(buf, conn->cache.buf, total);
378
379 conn->cache.len -= total;
380 conn->cache.pos += total;
381 len -= total;
382 buf += total;
383 }
384
385 while (len > 0) {
386 /*
387 * The socket is non-blocking. Instead of the canonical
388 * select() -> read(), we do the following:
389 *
390 * 1) call read() or SSL_read().
391 * 2) if an error occurred, return -1.
392 * 3) if we received data but we still expect more,
393 * update our counters and loop.
394 * 4) if read() or SSL_read() signaled EOF, return.
395 * 5) if we did not receive any data but we're not at EOF,
396 * call select().
397 *
398 * In the SSL case, this is necessary because if we
399 * receive a close notification, we have to call
400 * SSL_read() one additional time after we've read
401 * everything we received.
402 *
403 * In the non-SSL case, it may improve performance (very
404 * slightly) when reading small amounts of data.
405 */
406 if (conn->ssl != NULL)
407 rlen = fetch_ssl_read(conn->ssl, buf, len);
408 else
409 rlen = fetch_nonssl_read(conn->sd, buf, len);
410 if (rlen == 0) {
411 conn->iseof = 1;
412 break;
413 } else if (rlen > 0) {
414 len -= rlen;
415 buf += rlen;
416 total += rlen;
417 continue;
418 } else if (rlen == FETCH_READ_ERROR) {
419 conn->iserr = errno;
420 if (errno == EINTR)
421 fetch_cache_data(conn, start, total);
422 return 0;
423 }
424 FD_ZERO(&readfds);
425 while (!FD_ISSET(conn->sd, &readfds)) {
426 FD_SET(conn->sd, &readfds);
427 if (quit_time > 0) {
428 gettimeofday(&now, NULL);
429 if (!timercmp(&timeout, &now, >)) {
430 conn->iserr = ETIMEDOUT;
431 return 0;
432 }
433 timersub(&timeout, &now, &delta);
434 }
435 errno = 0;
436 if (select(conn->sd + 1, &readfds, NULL, NULL,
437 quit_time > 0 ? &delta : NULL) < 0) {
438 if (errno == EINTR)
439 continue;
440 conn->iserr = errno;
441 return 0;
442 }
443 }
444 }
445 return total;
446 }
447
448 #define MIN_BUF_SIZE 1024
449
450 /*
451 * Read a line of text from a connection w/ timeout
452 */
453 char *
454 fetch_getln(char *str, int size, struct fetch_connect *conn)
455 {
456 size_t tmpsize;
457 size_t len;
458 char c;
459
460 if (conn->buf == NULL) {
461 if ((conn->buf = malloc(MIN_BUF_SIZE)) == NULL) {
462 errno = ENOMEM;
463 conn->iserr = 1;
464 return NULL;
465 }
466 conn->bufsize = MIN_BUF_SIZE;
467 }
468
469 if (conn->iserr || conn->iseof)
470 return NULL;
471
472 if (conn->buflen - conn->bufpos > 0)
473 goto done;
474
475 conn->buf[0] = '\0';
476 conn->bufpos = 0;
477 conn->buflen = 0;
478 do {
479 len = fetch_read(&c, sizeof(c), 1, conn);
480 if (len == 0) {
481 if (conn->iserr)
482 return NULL;
483 if (conn->iseof)
484 break;
485 abort();
486 }
487 conn->buf[conn->buflen++] = c;
488 if (conn->buflen == conn->bufsize) {
489 char *tmp = conn->buf;
490 tmpsize = conn->bufsize * 2 + 1;
491 if ((tmp = realloc(tmp, tmpsize)) == NULL) {
492 errno = ENOMEM;
493 conn->iserr = 1;
494 return NULL;
495 }
496 conn->buf = tmp;
497 conn->bufsize = tmpsize;
498 }
499 } while (c != '\n');
500
501 if (conn->buflen == 0)
502 return NULL;
503 done:
504 tmpsize = MIN(size - 1, (int)(conn->buflen - conn->bufpos));
505 memcpy(str, conn->buf + conn->bufpos, tmpsize);
506 str[tmpsize] = '\0';
507 conn->bufpos += tmpsize;
508 return str;
509 }
510
511 int
512 fetch_getline(struct fetch_connect *conn, char *buf, size_t buflen,
513 const char **errormsg)
514 {
515 size_t len;
516 int rv;
517
518 if (fetch_getln(buf, buflen, conn) == NULL) {
519 if (conn->iseof) { /* EOF */
520 rv = -2;
521 if (errormsg)
522 *errormsg = "\nEOF received";
523 } else { /* error */
524 rv = -1;
525 if (errormsg)
526 *errormsg = "Error encountered";
527 }
528 fetch_clearerr(conn);
529 return rv;
530 }
531 len = strlen(buf);
532 if (buf[len - 1] == '\n') { /* clear any trailing newline */
533 buf[--len] = '\0';
534 } else if (len == buflen - 1) { /* line too long */
535 while (1) {
536 char c;
537 size_t rlen = fetch_read(&c, sizeof(c), 1, conn);
538 if (rlen == 0 || c == '\n')
539 break;
540 }
541 if (errormsg)
542 *errormsg = "Input line is too long";
543 fetch_clearerr(conn);
544 return -3;
545 }
546 if (errormsg)
547 *errormsg = NULL;
548 return len;
549 }
550
551 void *
552 fetch_start_ssl(int sock, const char *servername)
553 {
554 SSL *ssl;
555 SSL_CTX *ctx;
556 int ret, ssl_err;
557
558 /* Init the SSL library and context */
559 if (!SSL_library_init()){
560 fprintf(ttyout, "SSL library init failed\n");
561 return NULL;
562 }
563
564 SSL_load_error_strings();
565
566 ctx = SSL_CTX_new(SSLv23_client_method());
567 SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
568
569 ssl = SSL_new(ctx);
570 if (ssl == NULL){
571 fprintf(ttyout, "SSL context creation failed\n");
572 SSL_CTX_free(ctx);
573 return NULL;
574 }
575 SSL_set_fd(ssl, sock);
576 if (!SSL_set_tlsext_host_name(ssl, __UNCONST(servername))) {
577 fprintf(ttyout, "SSL hostname setting failed\n");
578 SSL_CTX_free(ctx);
579 return NULL;
580 }
581 while ((ret = SSL_connect(ssl)) == -1) {
582 ssl_err = SSL_get_error(ssl, ret);
583 if (ssl_err != SSL_ERROR_WANT_READ &&
584 ssl_err != SSL_ERROR_WANT_WRITE) {
585 ERR_print_errors_fp(ttyout);
586 SSL_free(ssl);
587 return NULL;
588 }
589 }
590
591 if (ftp_debug && verbose) {
592 X509 *cert;
593 X509_NAME *name;
594 char *str;
595
596 fprintf(ttyout, "SSL connection established using %s\n",
597 SSL_get_cipher(ssl));
598 cert = SSL_get_peer_certificate(ssl);
599 name = X509_get_subject_name(cert);
600 str = X509_NAME_oneline(name, 0, 0);
601 fprintf(ttyout, "Certificate subject: %s\n", str);
602 free(str);
603 name = X509_get_issuer_name(cert);
604 str = X509_NAME_oneline(name, 0, 0);
605 fprintf(ttyout, "Certificate issuer: %s\n", str);
606 free(str);
607 }
608
609 return ssl;
610 }
611
612
613 void
614 fetch_set_ssl(struct fetch_connect *conn, void *ssl)
615 {
616 conn->ssl = ssl;
617 }
618