diff options
author | Natanael Copa <ncopa@alpinelinux.org> | 2018-05-30 09:52:20 +0000 |
---|---|---|
committer | Natanael Copa <ncopa@alpinelinux.org> | 2018-05-30 10:44:48 +0000 |
commit | 1d0560a9b6b5597b191e5aff69a31c2fe0aba273 (patch) | |
tree | 23e808e7b123643b55e2eb07101b8467b429b975 /main/busybox/ssl_client.c | |
parent | 782065ccea8a1415f01f568f5bce411898f4d7fb (diff) | |
download | aports-1d0560a9b6b5597b191e5aff69a31c2fe0aba273.tar.bz2 aports-1d0560a9b6b5597b191e5aff69a31c2fe0aba273.tar.xz |
main/busybox: properly fix wget https support
fix busybox wget https support by using an external ssl_client helper
for https.
Disable the use of external openssl. This was fixed to check
certificates as a temporary solution. openssl can not produce any useful
error messages on certificate errors. It is big. So we simply disable
its use.
For dynamic busybox we disable the internal ssl_client and the internal
(broken) tls code, and build our own ssl_client which properly verifies
the certificates.
For the static busybox we enable the internal ssl_client and tls code,
but we only allow its use with --no-check-certificates. This is so we
still can fetch things from https in an emergency situation.
We auto-install ssl_client if both libssl and busybox are installed. This
is to keep backwards compatibility.
Diffstat (limited to 'main/busybox/ssl_client.c')
-rw-r--r-- | main/busybox/ssl_client.c | 158 |
1 files changed, 158 insertions, 0 deletions
diff --git a/main/busybox/ssl_client.c b/main/busybox/ssl_client.c new file mode 100644 index 0000000000..8aa558e70f --- /dev/null +++ b/main/busybox/ssl_client.c @@ -0,0 +1,158 @@ +#include <err.h> +#include <errno.h> +#include <poll.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include <tls.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 copy_from_stdin_to_tls(struct tls *ctx, 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 = tls_write(ctx, &buf[i], n); + if (r == TLS_WANT_POLLIN || r == TLS_WANT_POLLOUT) + continue; + if (r < 0) + err(1, "tls_write: %s", tls_error(ctx)); + i += r; + n -= r; + } +} + +static int copy_from_tls_to_stdout(struct tls *ctx) +{ + static size_t buf[BUFSIZE]; + ssize_t n,r; + int i = 0; + + dbg("DEBUG: data from TLS\n"); + do { + n = tls_read(ctx, buf, sizeof(buf)); + } while (n == TLS_WANT_POLLIN || r == TLS_WANT_POLLOUT); + if (n < 0) + err(1, "tls read: %s", tls_error(ctx)); + + 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; +} + +int do_poll(struct pollfd *fds, int nfds) +{ + int r; + while ((r = poll(fds, nfds, -1)) < 0) { + if (errno != EINTR && errno != ENOMEM) + err(1, "poll"); + } + return r; +} + +static void copy_loop(struct tls *ctx, int sfd) +{ + struct pollfd fds[2] = { + { .fd = STDIN_FILENO, .events = POLLIN }, + { .fd = sfd, .events = POLLIN }, + }; + + while (1) { + int r = do_poll(fds, 2); + if (fds[0].revents) + copy_from_stdin_to_tls(ctx, &fds[0].fd); + + if (fds[1].revents && copy_from_tls_to_stdout(ctx)) + 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;; + const char *sni = NULL; + struct tls_config *tc; + struct tls *ctx; + int insecure = 0; + + 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); + } + } + + if (tls_init() == -1) + errx(1, "tls_init() failed"); + + if ((ctx = tls_client()) == NULL) + errx(1, "tls_client() failed"); + + if (insecure) { + if ((tc = tls_config_new()) == NULL) + errx(1, "tls_config_new() failed"); + tls_config_insecure_noverifycert(tc); + tls_config_insecure_noverifyname(tc); + tls_config_insecure_noverifytime(tc); + if (tls_configure(ctx, tc) == -1) + err(1, "tls_configure: %s", tls_error(ctx)); + tls_config_free(tc); + } + + if (tls_connect_fds(ctx, sfd, sfd, sni) == -1) + errx(1, "%s: TLS connect failed", sni); + + if (tls_handshake(ctx) == -1) + errx(1, "%s: %s", sni, tls_error(ctx)); + + copy_loop(ctx, sfd); + tls_close(ctx); + return 0; +} |