diff options
-rw-r--r-- | usr.bin/ftp/Makefile | 6 | ||||
-rw-r--r-- | usr.bin/ftp/fetch.c | 328 | ||||
-rw-r--r-- | usr.bin/ftp/ftp_var.h | 13 | ||||
-rw-r--r-- | usr.bin/ftp/main.c | 42 |
4 files changed, 74 insertions, 315 deletions
diff --git a/usr.bin/ftp/Makefile b/usr.bin/ftp/Makefile index 876cb494f4e..4d1fc634905 100644 --- a/usr.bin/ftp/Makefile +++ b/usr.bin/ftp/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.25 2009/05/05 19:35:30 martynas Exp $ +# $OpenBSD: Makefile,v 1.26 2014/07/14 09:26:27 jsing Exp $ # Define SMALL to disable command line editing and https support #CFLAGS+=-DSMALL @@ -17,8 +17,8 @@ SRCS= cmds.c cmdtab.c complete.c cookie.c domacro.c fetch.c ftp.c \ CPPFLAGS+= -DINET6 -LDADD+= -ledit -lcurses -lutil -lssl -lcrypto -DPADD+= ${LIBEDIT} ${LIBCURSES} ${LIBUTIL} +LDADD+= -ledit -lcurses -lutil -lressl -lssl -lcrypto +DPADD+= ${LIBEDIT} ${LIBCURSES} ${LIBUTIL} ${LIBRESSL} ${LIBSSL} ${LIBCRYPTO} LDSTATIC= ${STATIC} #COPTS+= -Wall -Wconversion -Wstrict-prototypes -Wmissing-prototypes diff --git a/usr.bin/ftp/fetch.c b/usr.bin/ftp/fetch.c index 0c07aa07abc..8a836128504 100644 --- a/usr.bin/ftp/fetch.c +++ b/usr.bin/ftp/fetch.c @@ -1,4 +1,4 @@ -/* $OpenBSD: fetch.c,v 1.125 2014/07/11 18:19:45 halex Exp $ */ +/* $OpenBSD: fetch.c,v 1.126 2014/07/14 09:26:27 jsing Exp $ */ /* $NetBSD: fetch.c,v 1.14 1997/08/18 10:20:20 lukem Exp $ */ /*- @@ -61,11 +61,9 @@ #include <resolv.h> #ifndef SMALL -#include <openssl/ssl.h> -#include <openssl/err.h> -#include <openssl/x509v3.h> +#include <ressl.h> #else /* !SMALL */ -#define SSL void +struct ressl; #endif /* !SMALL */ #include "ftp_var.h" @@ -77,18 +75,13 @@ void abortfile(int); char hextochar(const char *); char *urldecode(const char *); char *recode_credentials(const char *_userinfo); -int ftp_printf(FILE *, SSL *, const char *, ...) __attribute__((format(printf, 3, 4))); -char *ftp_readline(FILE *, SSL *, size_t *); -size_t ftp_read(FILE *, SSL *, char *, size_t); +int ftp_printf(FILE *, struct ressl *, const char *, ...) __attribute__((format(printf, 3, 4))); +char *ftp_readline(FILE *, struct ressl *, size_t *); +size_t ftp_read(FILE *, struct ressl *, char *, size_t); #ifndef SMALL int proxy_connect(int, char *, char *); -int SSL_vprintf(SSL *, const char *, va_list); -char *SSL_readline(SSL *, size_t *); -int ssl_match_hostname(char *, char *); -int ssl_check_subject_altname(X509 *, char *); -int ssl_check_common_name(X509 *, char *); -int ssl_check_hostname(X509 *, char *); -SSL_CTX *ssl_get_ssl_ctx(void); +int SSL_vprintf(struct ressl *, const char *, va_list); +char *SSL_readline(struct ressl *, size_t *); #endif /* !SMALL */ #define FTP_URL "ftp://" /* ftp URL prefix */ @@ -172,211 +165,6 @@ url_encode(const char *path) return (epath); } -#ifndef SMALL -int -ssl_match_hostname(char *cert_hostname, char *hostname) -{ - if (strcasecmp(cert_hostname, hostname) == 0) - return 0; - - /* wildcard match? */ - if (cert_hostname[0] == '*') { - char *cert_domain, *domain; - - cert_domain = &cert_hostname[1]; - if (cert_domain[0] != '.') - return -1; - if (strlen(cert_domain) == 1) - return -1; - - domain = strchr(hostname, '.'); - /* no wildcard match against a hostname with no domain part */ - if (domain == NULL || strlen(domain) == 1) - return -1; - - if (strcasecmp(cert_domain, domain) == 0) - return 0; - } - - return -1; -} - -int -ssl_check_subject_altname(X509 *cert, char *host) -{ - STACK_OF(GENERAL_NAME) *altname_stack = NULL; - union { struct in_addr ip4; struct in6_addr ip6; } addrbuf; - int addrlen, type; - int count, i; - int rv = -1; - - altname_stack = - X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL); - if (altname_stack == NULL) - return -1; - - if (inet_pton(AF_INET, host, &addrbuf) == 1) { - type = GEN_IPADD; - addrlen = 4; - } else if (inet_pton(AF_INET6, host, &addrbuf) == 1) { - type = GEN_IPADD; - addrlen = 16; - } else - type = GEN_DNS; - - count = sk_GENERAL_NAME_num(altname_stack); - for (i = 0; i < count; i++) { - GENERAL_NAME *altname; - - altname = sk_GENERAL_NAME_value(altname_stack, i); - - if (altname->type != type) - continue; - - if (type == GEN_DNS) { - unsigned char *data; - int format; - - format = ASN1_STRING_type(altname->d.dNSName); - if (format == V_ASN1_IA5STRING) { - data = ASN1_STRING_data(altname->d.dNSName); - - if (ASN1_STRING_length(altname->d.dNSName) != - (int)strlen(data)) { - fprintf(ttyout, "%s: NUL byte in " - "subjectAltName, probably a " - "malicious certificate.\n", - getprogname()); - rv = -2; - break; - } - - if (ssl_match_hostname(data, host) == 0) { - rv = 0; - break; - } - } else - fprintf(ttyout, "%s: unhandled subjectAltName " - "dNSName encoding (%d)\n", getprogname(), - format); - - } else if (type == GEN_IPADD) { - unsigned char *data; - int datalen; - - datalen = ASN1_STRING_length(altname->d.iPAddress); - data = ASN1_STRING_data(altname->d.iPAddress); - - if (datalen == addrlen && - memcmp(data, &addrbuf, addrlen) == 0) { - rv = 0; - break; - } - } - } - - sk_GENERAL_NAME_free(altname_stack); - return rv; -} - -int -ssl_check_common_name(X509 *cert, char *host) -{ - X509_NAME *name; - char *common_name = NULL; - int common_name_len; - int rv = -1; - - name = X509_get_subject_name(cert); - if (name == NULL) - goto out; - - common_name_len = X509_NAME_get_text_by_NID(name, NID_commonName, - NULL, 0); - if (common_name_len < 0) - goto out; - - common_name = calloc(common_name_len + 1, 1); - if (common_name == NULL) - goto out; - - X509_NAME_get_text_by_NID(name, NID_commonName, common_name, - common_name_len + 1); - - /* NUL bytes in CN? */ - if (common_name_len != (int)strlen(common_name)) { - fprintf(ttyout, "%s: NUL byte in Common Name field, " - "probably a malicious certificate.\n", getprogname()); - rv = -2; - goto out; - } - - if (ssl_match_hostname(common_name, host) == 0) - rv = 0; -out: - free(common_name); - return rv; -} - -int -ssl_check_hostname(X509 *cert, char *host) -{ - int rv; - - rv = ssl_check_subject_altname(cert, host); - if (rv == 0 || rv == -2) - return rv; - - return ssl_check_common_name(cert, host); -} - -SSL_CTX * -ssl_get_ssl_ctx(void) -{ - static SSL_CTX *ssl_ctx = NULL; - static int libssl_loaded = 0; - - if (ssl_ctx != NULL) - return ssl_ctx; - - if (!libssl_loaded) { - SSL_library_init(); - SSL_load_error_strings(); - libssl_loaded = 1; - } - - ssl_ctx = SSL_CTX_new(SSLv23_client_method()); - if (ssl_ctx == NULL) - goto err; - - if (ssl_verify) { - if (ssl_ca_file == NULL && ssl_ca_path == NULL) - ssl_ca_file = _PATH_SSL_CAFILE; - - if (SSL_CTX_load_verify_locations(ssl_ctx, - ssl_ca_file, ssl_ca_path) != 1) - goto err; - - SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, NULL); - if (ssl_verify_depth != -1) - SSL_CTX_set_verify_depth(ssl_ctx, - ssl_verify_depth); - } - - if (ssl_ciphers != NULL && - SSL_CTX_set_cipher_list(ssl_ctx, ssl_ciphers) == -1) - goto err; - - return ssl_ctx; -err: - if (ssl_ctx != NULL) { - SSL_CTX_free(ssl_ctx); - ssl_ctx = NULL; - } - return NULL; -} -#endif - /* * Retrieve URL, via the proxy in $proxyvar if necessary. * Modifies the string argument given. @@ -404,9 +192,8 @@ url_get(const char *origline, const char *proxyenv, const char *outfile) char *locbase, *full_host = NULL; const char *scheme; int ishttpurl = 0, ishttpsurl = 0; - SSL_CTX *ssl_ctx = NULL; #endif /* !SMALL */ - SSL *ssl = NULL; + struct ressl *ssl = NULL; int status; int save_errno; const size_t buflen = 128 * 1024; @@ -799,62 +586,28 @@ again: #ifndef SMALL if (ishttpsurl) { - union { struct in_addr ip4; struct in6_addr ip6; } addrbuf; - if (proxyenv && sslpath) { ishttpsurl = 0; proxyurl = NULL; path = sslpath; } - ssl_ctx = ssl_get_ssl_ctx(); - if (ssl_ctx == NULL) { - ERR_print_errors_fp(ttyout); + if (ressl_init() != 0) { + fprintf(ttyout, "SSL initialisation failed\n"); goto cleanup_url_get; } - ssl = SSL_new(ssl_ctx); - if (ssl == NULL) { - ERR_print_errors_fp(ttyout); + if ((ssl = ressl_client()) == NULL) { + fprintf(ttyout, "failed to create SSL client\n"); goto cleanup_url_get; } - if (SSL_set_fd(ssl, s) == 0) { - ERR_print_errors_fp(ttyout); + if (ressl_configure(ssl, ressl_config) != 0) { + fprintf(ttyout, "SSL configuration failure: %s\n", + ressl_error(ssl)); goto cleanup_url_get; } - /* - * RFC4366 (SNI): Literal IPv4 and IPv6 addresses are not - * permitted in "HostName". - */ - if (inet_pton(AF_INET, host, &addrbuf) != 1 && - inet_pton(AF_INET6, host, &addrbuf) != 1) { - if (SSL_set_tlsext_host_name(ssl, host) == 0) { - ERR_print_errors_fp(ttyout); - goto cleanup_url_get; - } - } - if (SSL_connect(ssl) <= 0) { - ERR_print_errors_fp(ttyout); + if (ressl_connect_socket(ssl, s, host) != 0) { + fprintf(ttyout, "SSL failure: %s\n", ressl_error(ssl)); goto cleanup_url_get; } - if (ssl_verify) { - X509 *cert; - - cert = SSL_get_peer_certificate(ssl); - if (cert == NULL) { - fprintf(ttyout, "%s: no server certificate\n", - getprogname()); - goto cleanup_url_get; - } - - if (ssl_check_hostname(cert, host) != 0) { - X509_free(cert); - fprintf(ttyout, "%s: host `%s' not present in" - " server certificate\n", - getprogname(), host); - goto cleanup_url_get; - } - - X509_free(cert); - } } else { fin = fdopen(s, "r+"); } @@ -1217,9 +970,9 @@ improper: cleanup_url_get: #ifndef SMALL - if (ssl) { - SSL_shutdown(ssl); - SSL_free(ssl); + if (ssl != NULL) { + ressl_close(ssl); + ressl_free(ssl); } free(full_host); free(credentials); @@ -1673,7 +1426,7 @@ isurl(const char *p) } char * -ftp_readline(FILE *fp, SSL *ssl, size_t *lenp) +ftp_readline(FILE *fp, struct ressl *ssl, size_t *lenp) { if (fp != NULL) return fparseln(fp, lenp, NULL, "\0\0\0", 0); @@ -1686,18 +1439,16 @@ ftp_readline(FILE *fp, SSL *ssl, size_t *lenp) } size_t -ftp_read(FILE *fp, SSL *ssl, char *buf, size_t len) +ftp_read(FILE *fp, struct ressl *ssl, char *buf, size_t len) { size_t ret; if (fp != NULL) ret = fread(buf, sizeof(char), len, fp); #ifndef SMALL else if (ssl != NULL) { - int nr; + size_t nr; - if (len > INT_MAX) - len = INT_MAX; - if ((nr = SSL_read(ssl, buf, (int)len)) <= 0) + if ((ret = ressl_read(ssl, buf, len, &nr)) != 0) ret = 0; else ret = nr; @@ -1709,7 +1460,7 @@ ftp_read(FILE *fp, SSL *ssl, char *buf, size_t len) } int -ftp_printf(FILE *fp, SSL *ssl, const char *fmt, ...) +ftp_printf(FILE *fp, struct ressl *ssl, const char *fmt, ...) { int ret; va_list ap; @@ -1720,7 +1471,7 @@ ftp_printf(FILE *fp, SSL *ssl, const char *fmt, ...) ret = vfprintf(fp, fmt, ap); #ifndef SMALL else if (ssl != NULL) - ret = SSL_vprintf((SSL*)ssl, fmt, ap); + ret = SSL_vprintf(ssl, fmt, ap); #endif /* !SMALL */ else ret = 0; @@ -1731,22 +1482,23 @@ ftp_printf(FILE *fp, SSL *ssl, const char *fmt, ...) #ifndef SMALL int -SSL_vprintf(SSL *ssl, const char *fmt, va_list ap) +SSL_vprintf(struct ressl *ssl, const char *fmt, va_list ap) { - int ret; char *string; + size_t nw; + int ret; if ((ret = vasprintf(&string, fmt, ap)) == -1) return ret; - ret = SSL_write(ssl, string, ret); + ret = ressl_write(ssl, string, ret, &nw); free(string); return ret; } char * -SSL_readline(SSL *ssl, size_t *lenp) +SSL_readline(struct ressl *ssl, size_t *lenp) { - size_t i, len; + size_t i, len, nr; char *buf, *q, c; int ret; @@ -1761,14 +1513,12 @@ SSL_readline(SSL *ssl, size_t *lenp) len *= 2; } again: - ret = SSL_read(ssl, &c, 1); - if (ret <= 0) { - if (SSL_get_error(ssl, ret) == SSL_ERROR_WANT_READ) - goto again; - else - errx(1, "SSL_read error: %u", - SSL_get_error(ssl, ret)); - } + ret = ressl_read(ssl, &c, 1, &nr); + if (ret == -2) + goto again; + if (ret != 0) + errx(1, "SSL read error: %u", ret); + buf[i] = c; if (c == '\n') break; diff --git a/usr.bin/ftp/ftp_var.h b/usr.bin/ftp/ftp_var.h index eef6ba2f854..5d8cf41ae91 100644 --- a/usr.bin/ftp/ftp_var.h +++ b/usr.bin/ftp/ftp_var.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ftp_var.h,v 1.34 2014/07/11 03:31:52 lteo Exp $ */ +/* $OpenBSD: ftp_var.h,v 1.35 2014/07/14 09:26:27 jsing Exp $ */ /* $NetBSD: ftp_var.h,v 1.18 1997/08/18 10:20:25 lukem Exp $ */ /* @@ -77,6 +77,8 @@ int fclose(FILE *); #endif +#include <ressl.h> + #include "stringlist.h" #include "extern.h" #include "small.h" @@ -232,12 +234,5 @@ FILE *ttyout; /* stdout or stderr, depending on interactive */ extern struct cmd cmdtab[]; #ifndef SMALL -extern char *ssl_ciphers; -extern char *ssl_ca_file; -extern char *ssl_ca_path; -extern int ssl_verify; -extern int ssl_verify_depth; -# ifndef _PATH_SSL_CAFILE -# define _PATH_SSL_CAFILE "/etc/ssl/cert.pem" -# endif +extern struct ressl_config *ressl_config; #endif /* !SMALL */ diff --git a/usr.bin/ftp/main.c b/usr.bin/ftp/main.c index 5d68d21b015..7631889a81e 100644 --- a/usr.bin/ftp/main.c +++ b/usr.bin/ftp/main.c @@ -1,4 +1,4 @@ -/* $OpenBSD: main.c,v 1.90 2014/07/14 05:54:12 deraadt Exp $ */ +/* $OpenBSD: main.c,v 1.91 2014/07/14 09:26:27 jsing Exp $ */ /* $NetBSD: main.c,v 1.24 1997/08/18 10:20:26 lukem Exp $ */ /* @@ -76,8 +76,10 @@ #include <string.h> #include <unistd.h> -#include "ftp_var.h" +#include <ressl.h> + #include "cmds.h" +#include "ftp_var.h" #ifndef SMALL char * const ssl_verify_opts[] = { @@ -95,11 +97,8 @@ char * const ssl_verify_opts[] = { "depth", NULL }; -char *ssl_ciphers; -int ssl_verify = 1; -int ssl_verify_depth = -1; -char *ssl_ca_file; -char *ssl_ca_path; + +struct ressl_config *ressl_config; #endif /* !SMALL */ int family = PF_UNSPEC; @@ -114,6 +113,9 @@ main(volatile int argc, char *argv[]) char *outfile = NULL; const char *errstr; int dumb_terminal = 0; +#ifndef SMALL + long long depth; +#endif ftpport = "ftp"; httpport = "http"; @@ -307,6 +309,12 @@ main(volatile int argc, char *argv[]) case 'S': #ifndef SMALL + if (ressl_config == NULL) { + ressl_config = ressl_config_new(); + if (ressl_config == NULL) + errx(1, "ressl config failed"); + } + cp = optarg; while (*cp) { char *str; @@ -314,34 +322,40 @@ main(volatile int argc, char *argv[]) case SSL_CAFILE: if (str == NULL) errx(1, "missing CA file"); - ssl_ca_file = str; + ressl_config_set_ca_file(ressl_config, + str); break; case SSL_CAPATH: if (str == NULL) errx(1, "missing CA directory" " path"); - ssl_ca_path = str; + ressl_config_set_ca_path(ressl_config, + str); break; case SSL_CIPHERS: if (str == NULL) errx(1, "missing cipher list"); - ssl_ciphers = str; + ressl_config_set_ciphers(ressl_config, + str); break; case SSL_DONTVERIFY: - ssl_verify = 0; + ressl_config_insecure_no_verify( + ressl_config); break; case SSL_DOVERIFY: - ssl_verify = 1; + ressl_config_verify(ressl_config); break; case SSL_VERIFYDEPTH: if (str == NULL) errx(1, "missing depth"); - ssl_verify_depth = strtonum(str, 0, - INT_MAX, &errstr); + depth = strtonum(str, 0, INT_MAX, + &errstr); if (errstr) errx(1, "certificate " "validation depth is %s", errstr); + ressl_config_set_verify_depth( + ressl_config, (int)depth); break; default: errx(1, "unknown -S suboption `%s'", |