mirror of
https://gitlab.alpinelinux.org/alpine/aports.git
synced 2025-04-20 00:16:38 +02:00
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
190 lines
3.3 KiB
C
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;
|
|
}
|