aboutsummaryrefslogtreecommitdiffstats
path: root/main/busybox/ssl_client.c
diff options
context:
space:
mode:
authorNatanael Copa <ncopa@alpinelinux.org>2018-05-30 09:52:20 +0000
committerNatanael Copa <ncopa@alpinelinux.org>2018-05-30 10:44:48 +0000
commit1d0560a9b6b5597b191e5aff69a31c2fe0aba273 (patch)
tree23e808e7b123643b55e2eb07101b8467b429b975 /main/busybox/ssl_client.c
parent782065ccea8a1415f01f568f5bce411898f4d7fb (diff)
downloadaports-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.c158
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;
+}