aports/main/busybox/ssl_client.c
Sertonix 3ad91a2f06 main/busybox: fix ssl error with domains ending with a dot
A trailing dot in a domain should be ignore but openssl doesn't[0]. So
removing it in ssl_client.

Try out with this command:
  busybox wget https://example.com./

[0]: https://github.com/openssl/openssl/issues/11560
2024-04-26 11:57:08 +00:00

190 lines
3.3 KiB
C

#include <err.h>
#include <errno.h>
#include <poll.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <openssl/err.h>
#include <openssl/ssl.h>
#include <openssl/x509v3.h>
#define BUFSIZE 16384
#define TLS_DEBUG 0
#if TLS_DEBUG
# define dbg(...) fprintf(stderr, __VA_ARGS__)
#else
# define dbg(...) ((void)0)
#endif
static void ssl_fatal(const char *msg)
{
ERR_print_errors_fp(stderr);
errx(1, "%s", msg);
}
static void copy_from_stdin_to_tls(SSL *ssl, int *fd)
{
static size_t buf[BUFSIZE];
ssize_t n;
int i = 0;
dbg("DEBUG: data from STDIN\n");
do {
n = read(STDIN_FILENO, buf, sizeof(buf));
dbg("read %zu\n", n);
} while (n < 0 && errno == EINTR);
if (n < 1) {
*fd = -1;
return;
}
while (n > 0) {
ssize_t r = SSL_write(ssl, &buf[i], n);
if (r < 0) {
if (SSL_get_error(ssl, r) == SSL_ERROR_WANT_WRITE) {
ERR_clear_error();
continue;
}
ssl_fatal("SSL_write");
}
i += r;
n -= r;
}
}
static int should_retry_read(SSL *ssl, int n)
{
if (n >= 0 || SSL_get_error(ssl, n) != SSL_ERROR_WANT_READ)
return 0;
ERR_clear_error();
return 1;
}
static int copy_from_tls_to_stdout(SSL *ssl)
{
static size_t buf[BUFSIZE];
ssize_t n,r;
int i = 0;
dbg("DEBUG: data from TLS\n");
do {
n = SSL_read(ssl, buf, sizeof(buf));
} while (should_retry_read(ssl, n));
if (n < 0)
ssl_fatal("SSL_read");
if (n == 0)
return 1;
while (n) {
r = write(STDOUT_FILENO, &buf[i], n);
if (r < 0)
err(1, "write");
i += r;
n -= r;
}
return 0;
}
void do_poll(struct pollfd *fds, int nfds)
{
while (poll(fds, nfds, -1) < 0) {
if (errno != EINTR && errno != ENOMEM)
err(1, "poll");
}
}
static void copy_loop(SSL *ssl, int sfd)
{
struct pollfd fds[2] = {
{ .fd = STDIN_FILENO, .events = POLLIN },
{ .fd = sfd, .events = POLLIN },
};
while (1) {
do_poll(fds, 2);
if (fds[0].revents) {
copy_from_stdin_to_tls(ssl, &fds[0].fd);
}
if (fds[1].revents && copy_from_tls_to_stdout(ssl))
break;
}
}
void usage(const char *prog, int ret) {
printf("usage: %s [-s FD] [-I] -n SNI\n", prog);
exit(ret);
}
int main(int argc, char *argv[])
{
int c, sfd = 1;;
char *sni = NULL;
int insecure = 0;
size_t sni_len;
SSL_CTX *ctx;
SSL *ssl = NULL;
while ((c = getopt(argc, argv, "hs:n:I")) != -1) {
switch (c) {
case 'h':
usage(argv[0], 0);
break;
case 's':
sfd = atoi(optarg);
break;
case 'n':
sni = optarg;
break;
case 'I':
insecure = 1;
break;
case '?':
usage(argv[0], 1);
}
}
/* openssl doesn't ignore a trailing dot in a domain on it's own.
* https://github.com/openssl/openssl/issues/11560
*/
if (sni && (sni_len = strlen(sni)) && sni[sni_len - 1] == '.')
sni[sni_len - 1] = '\0';
OPENSSL_init_ssl(0, NULL);
if ((ctx = SSL_CTX_new(TLS_client_method())) == NULL)
ssl_fatal("SSL_CTX_new");
SSL_CTX_set_default_verify_paths(ctx);
if ((ssl = SSL_new(ctx)) == NULL)
ssl_fatal("SSL_new");
SSL_set_fd(ssl, sfd);
SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
SSL_set_hostflags(ssl, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
if (SSL_set_tlsext_host_name(ssl, sni) != 1)
ssl_fatal("SSL_set_tlsext_host_name");
if (SSL_set1_host(ssl, sni) != 1)
ssl_fatal(sni);
if (!insecure) {
SSL_set_verify(ssl, SSL_VERIFY_PEER, NULL);
}
ERR_clear_error();
if (SSL_connect(ssl) != 1)
ssl_fatal("SSL_connect");
copy_loop(ssl, sfd);
SSL_CTX_free(ctx);
return 0;
}