1 /* $NetBSD: ssl.c,v 1.2 2012/12/24 22:12:28 christos Exp $ */
4 * Copyright (c) 1998-2004 Dag-Erling Coïdan Smørgrav
5 * Copyright (c) 2008, 2010 Joerg Sonnenberger <joerg@NetBSD.org>
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer
13 * in this position and unchanged.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. The name of the author may not be used to endorse or promote products
18 * derived from this software without specific prior written permission
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 * $FreeBSD: common.c,v 1.53 2007/12/19 00:26:36 des Exp $
34 #include <sys/cdefs.h>
36 __RCSID("$NetBSD: ssl.c,v 1.2 2012/12/24 22:12:28 christos Exp $");
43 #include <sys/param.h>
44 #include <sys/select.h>
47 #include <netinet/tcp.h>
48 #include <netinet/in.h>
49 #include <openssl/crypto.h>
50 #include <openssl/x509.h>
51 #include <openssl/pem.h>
52 #include <openssl/ssl.h>
53 #include <openssl/err.h>
57 extern int quit_time, verbose, ftp_debug;
60 struct fetch_connect {
61 int sd; /* file/socket descriptor */
62 char *buf; /* buffer */
63 size_t bufsize; /* buffer size */
64 size_t bufpos; /* position of buffer */
65 size_t buflen; /* length of buffer contents */
66 struct { /* data cached after an
76 SSL *ssl; /* SSL handle */
80 * Write a vector to a connection w/ timeout
81 * Note: can modify the iovec.
84 fetch_writev(struct fetch_connect *conn, struct iovec *iov, int iovcnt)
86 struct timeval now, timeout, delta;
93 gettimeofday(&timeout, NULL);
94 timeout.tv_sec += quit_time;
99 while (quit_time > 0 && !FD_ISSET(conn->sd, &writefds)) {
100 FD_SET(conn->sd, &writefds);
101 gettimeofday(&now, NULL);
102 delta.tv_sec = timeout.tv_sec - now.tv_sec;
103 delta.tv_usec = timeout.tv_usec - now.tv_usec;
104 if (delta.tv_usec < 0) {
105 delta.tv_usec += 1000000;
108 if (delta.tv_sec < 0) {
113 r = select(conn->sd + 1, NULL, &writefds, NULL, &delta);
121 if (conn->ssl != NULL)
122 len = SSL_write(conn->ssl, iov->iov_base, iov->iov_len);
124 len = writev(conn->sd, iov, iovcnt);
126 /* we consider a short write a failure */
127 /* XXX perhaps we shouldn't in the SSL case */
137 while (iovcnt > 0 && len >= (ssize_t)iov->iov_len) {
144 iov->iov_base = (char *)iov->iov_base + len;
151 * Write to a connection w/ timeout
154 fetch_write(struct fetch_connect *conn, const char *str, size_t len)
158 iov[0].iov_base = (char *)__UNCONST(str);
159 iov[0].iov_len = len;
160 return fetch_writev(conn, iov, 1);
164 * Send a formatted line; optionally echo to terminal
167 fetch_printf(struct fetch_connect *conn, const char *fmt, ...)
175 len = vasprintf(&msg, fmt, ap);
183 r = fetch_write(conn, msg, len);
189 fetch_fileno(struct fetch_connect *conn)
196 fetch_error(struct fetch_connect *conn)
203 fetch_clearerr(struct fetch_connect *conn)
210 fetch_flush(struct fetch_connect *conn)
217 setsockopt(conn->sd, IPPROTO_TCP, TCP_NOPUSH, &v, sizeof(v));
220 setsockopt(conn->sd, IPPROTO_TCP, TCP_NODELAY, &v, sizeof(v));
226 struct fetch_connect *
227 fetch_open(const char *fname, const char *fmode)
229 struct fetch_connect *conn;
232 fd = open(fname, O_RDONLY); /* XXX: fmode */
236 if ((conn = calloc(1, sizeof(*conn))) == NULL) {
247 struct fetch_connect *
248 fetch_fdopen(int sd, const char *fmode)
250 struct fetch_connect *conn;
251 #if defined(SO_NOSIGPIPE) || defined(TCP_NOPUSH)
255 if ((conn = calloc(1, sizeof(*conn))) == NULL)
260 fcntl(sd, F_SETFD, FD_CLOEXEC);
262 setsockopt(sd, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof(opt));
265 setsockopt(sd, IPPROTO_TCP, TCP_NOPUSH, &opt, sizeof(opt));
271 fetch_close(struct fetch_connect *conn)
278 rv = close(conn->sd);
283 free(conn->cache.buf);
290 #define FETCH_READ_WAIT -2
291 #define FETCH_READ_ERROR -1
294 fetch_ssl_read(SSL *ssl, void *buf, size_t len)
299 rlen = SSL_read(ssl, buf, len);
301 ssl_err = SSL_get_error(ssl, rlen);
302 if (ssl_err == SSL_ERROR_WANT_READ ||
303 ssl_err == SSL_ERROR_WANT_WRITE) {
304 return FETCH_READ_WAIT;
306 ERR_print_errors_fp(ttyout);
307 return FETCH_READ_ERROR;
313 fetch_nonssl_read(int sd, void *buf, size_t len)
317 rlen = read(sd, buf, len);
319 if (errno == EAGAIN || errno == EINTR)
320 return FETCH_READ_WAIT;
321 return FETCH_READ_ERROR;
327 * Cache some data that was read from a socket but cannot be immediately
328 * returned because of an interrupted system call.
331 fetch_cache_data(struct fetch_connect *conn, char *src, size_t nbytes)
334 if (conn->cache.size < nbytes) {
335 char *tmp = realloc(conn->cache.buf, nbytes);
339 conn->cache.buf = tmp;
340 conn->cache.size = nbytes;
343 memcpy(conn->cache.buf, src, nbytes);
344 conn->cache.len = nbytes;
350 fetch_read(void *ptr, size_t size, size_t nmemb, struct fetch_connect *conn)
352 struct timeval now, timeout, delta;
359 gettimeofday(&timeout, NULL);
360 timeout.tv_sec += quit_time;
367 if (conn->cache.len > 0) {
369 * The last invocation of fetch_read was interrupted by a
370 * signal after some data had been read from the socket. Copy
371 * the cached data into the supplied buffer before trying to
372 * read from the socket again.
374 total = (conn->cache.len < len) ? conn->cache.len : len;
375 memcpy(buf, conn->cache.buf, total);
377 conn->cache.len -= total;
378 conn->cache.pos += total;
385 * The socket is non-blocking. Instead of the canonical
386 * select() -> read(), we do the following:
388 * 1) call read() or SSL_read().
389 * 2) if an error occurred, return -1.
390 * 3) if we received data but we still expect more,
391 * update our counters and loop.
392 * 4) if read() or SSL_read() signaled EOF, return.
393 * 5) if we did not receive any data but we're not at EOF,
396 * In the SSL case, this is necessary because if we
397 * receive a close notification, we have to call
398 * SSL_read() one additional time after we've read
399 * everything we received.
401 * In the non-SSL case, it may improve performance (very
402 * slightly) when reading small amounts of data.
404 if (conn->ssl != NULL)
405 rlen = fetch_ssl_read(conn->ssl, buf, len);
407 rlen = fetch_nonssl_read(conn->sd, buf, len);
410 } else if (rlen > 0) {
415 } else if (rlen == FETCH_READ_ERROR) {
417 fetch_cache_data(conn, start, total);
421 while (!FD_ISSET(conn->sd, &readfds)) {
422 FD_SET(conn->sd, &readfds);
424 gettimeofday(&now, NULL);
425 if (!timercmp(&timeout, &now, >)) {
429 timersub(&timeout, &now, &delta);
432 if (select(conn->sd + 1, &readfds, NULL, NULL,
433 quit_time > 0 ? &delta : NULL) < 0) {
443 #define MIN_BUF_SIZE 1024
446 * Read a line of text from a connection w/ timeout
449 fetch_getln(char *str, int size, struct fetch_connect *conn)
455 if (conn->buf == NULL) {
456 if ((conn->buf = malloc(MIN_BUF_SIZE)) == NULL) {
461 conn->bufsize = MIN_BUF_SIZE;
464 if (conn->iserr || conn->iseof)
467 if (conn->buflen - conn->bufpos > 0)
474 len = fetch_read(&c, sizeof(c), 1, conn);
483 conn->buf[conn->buflen++] = c;
484 if (conn->buflen == conn->bufsize) {
485 char *tmp = conn->buf;
486 tmpsize = conn->bufsize * 2 + 1;
487 if ((tmp = realloc(tmp, tmpsize)) == NULL) {
493 conn->bufsize = tmpsize;
497 if (conn->buflen == 0)
500 tmpsize = MIN(size - 1, (int)(conn->buflen - conn->bufpos));
501 memcpy(str, conn->buf + conn->bufpos, tmpsize);
503 conn->bufpos += tmpsize;
508 fetch_getline(struct fetch_connect *conn, char *buf, size_t buflen,
509 const char **errormsg)
514 if (fetch_getln(buf, buflen, conn) == NULL) {
515 if (conn->iseof) { /* EOF */
518 *errormsg = "\nEOF received";
522 *errormsg = "Error encountered";
524 fetch_clearerr(conn);
528 if (buf[len - 1] == '\n') { /* clear any trailing newline */
530 } else if (len == buflen - 1) { /* line too long */
533 ssize_t rlen = fetch_read(&c, sizeof(c), 1, conn);
534 if (rlen <= 0 || c == '\n')
538 *errormsg = "Input line is too long";
539 fetch_clearerr(conn);
548 fetch_start_ssl(int sock)
554 /* Init the SSL library and context */
555 if (!SSL_library_init()){
556 fprintf(ttyout, "SSL library init failed\n");
560 SSL_load_error_strings();
562 ctx = SSL_CTX_new(SSLv23_client_method());
563 SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
567 fprintf(ttyout, "SSL context creation failed\n");
571 SSL_set_fd(ssl, sock);
572 while ((ret = SSL_connect(ssl)) == -1) {
573 ssl_err = SSL_get_error(ssl, ret);
574 if (ssl_err != SSL_ERROR_WANT_READ &&
575 ssl_err != SSL_ERROR_WANT_WRITE) {
576 ERR_print_errors_fp(ttyout);
582 if (ftp_debug && verbose) {
587 fprintf(ttyout, "SSL connection established using %s\n",
588 SSL_get_cipher(ssl));
589 cert = SSL_get_peer_certificate(ssl);
590 name = X509_get_subject_name(cert);
591 str = X509_NAME_oneline(name, 0, 0);
592 fprintf(ttyout, "Certificate subject: %s\n", str);
594 name = X509_get_issuer_name(cert);
595 str = X509_NAME_oneline(name, 0, 0);
596 fprintf(ttyout, "Certificate issuer: %s\n", str);
605 fetch_set_ssl(struct fetch_connect *conn, void *ssl)