Content-Length: 5806 | pFad | https://ftp.openbsd.org/pub/OpenBSD/patches/5.5/common/003_ftp.patch.sig
untrusted comment: signature from openbsd 5.5 base secret key
RWRGy8gxk9N930zY+mHlRyBObN2mIoaUWYLZYGZXiD8Uu9/v4Pgb+rIOtmedlfOfwTsqLjFyzjPWEECAUmjft/nw96q1XTJPOwA=
OpenBSD 5.5 errata 3, April 9, 2014: The ftp(1) client would fail to
check the server hostname when connecting to an https website. This
allowed any trusted CA-signed certificate to impersonate any other website.
Apply patch using:
signify -Vep /etc/signify/openbsd-55-base.pub -x 003_ftp.patch.sig \
-m - | (cd /usr/src && patch -p0)
Then build and install ftp:
cd /usr/src/usr.bin/ftp
make obj
make
make install
Index: usr.bin/ftp/fetch.c
===================================================================
RCS file: /cvs/src/usr.bin/ftp/fetch.c,v
retrieving revision 1.114
diff -u -p -r1.114 fetch.c
--- usr.bin/ftp/fetch.c 2 Mar 2014 17:57:18 -0000 1.114
+++ usr.bin/ftp/fetch.c 9 Apr 2014 11:34:49 -0000
@@ -63,6 +63,7 @@
#ifndef SMALL
#include
#include
+#include
#else /* !SMALL */
#define SSL void
#endif /* !SMALL */
@@ -82,6 +83,10 @@ size_t ftp_read(FILE *, SSL *, char *,
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 *);
#endif /* !SMALL */
#define FTP_URL "ftp://" /* ftp URL prefix */
@@ -167,6 +172,165 @@ 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);
+}
+#endif
+
/*
* Retrieve URL, via the proxy in $proxyvar if necessary.
* Modifies the string argument given.
@@ -638,6 +802,25 @@ again:
if (SSL_connect(ssl) <= 0) {
ERR_print_errors_fp(ttyout);
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) {
+ 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+");
--- a PPN by Garber Painting Akron. With Image Size Reduction included!Fetched URL: https://ftp.openbsd.org/pub/OpenBSD/patches/5.5/common/003_ftp.patch.sig
Alternative Proxies:
Alternative Proxy
pFad Proxy
pFad v3 Proxy
pFad v4 Proxy