-/* $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 $ */
/*-
#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"
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 */
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.
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;
#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+");
}
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);
}
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);
}
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;
}
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;
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;
#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;
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;