aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/libbb.h88
-rw-r--r--networking/ssl_client.c55
-rw-r--r--networking/tls.c151
-rw-r--r--networking/wget.c102
4 files changed, 221 insertions, 175 deletions
diff --git a/include/libbb.h b/include/libbb.h
index 87f89c76d..ba3b1479e 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -355,6 +355,27 @@ extern char *skip_dev_pfx(const char *tty_name) FAST_FUNC;
extern char *strrstr(const char *haystack, const char *needle) FAST_FUNC;
+/* dmalloc will redefine these to it's own implementation. It is safe
+ * to have the prototypes here unconditionally. */
+void *malloc_or_warn(size_t size) FAST_FUNC RETURNS_MALLOC;
+void *xmalloc(size_t size) FAST_FUNC RETURNS_MALLOC;
+void *xzalloc(size_t size) FAST_FUNC RETURNS_MALLOC;
+void *xrealloc(void *old, size_t size) FAST_FUNC;
+/* After v = xrealloc_vector(v, SHIFT, idx) it's ok to use
+ * at least v[idx] and v[idx+1], for all idx values.
+ * SHIFT specifies how many new elements are added (1:2, 2:4, ..., 8:256...)
+ * when all elements are used up. New elements are zeroed out.
+ * xrealloc_vector(v, SHIFT, idx) *MUST* be called with consecutive IDXs -
+ * skipping an index is a bad bug - it may miss a realloc!
+ */
+#define xrealloc_vector(vector, shift, idx) \
+ xrealloc_vector_helper((vector), (sizeof((vector)[0]) << 8) + (shift), (idx))
+void* xrealloc_vector_helper(void *vector, unsigned sizeof_and_shift, int idx) FAST_FUNC;
+char *xstrdup(const char *s) FAST_FUNC RETURNS_MALLOC;
+char *xstrndup(const char *s, int n) FAST_FUNC RETURNS_MALLOC;
+void *xmemdup(const void *s, int n) FAST_FUNC RETURNS_MALLOC;
+
+
//TODO: supply a pointer to char[11] buffer (avoid statics)?
extern const char *bb_mode_string(mode_t mode) FAST_FUNC;
extern int is_directory(const char *name, int followLinks) FAST_FUNC;
@@ -692,6 +713,52 @@ struct hostent *xgethostbyname(const char *name) FAST_FUNC;
// Also mount.c and inetd.c are using gethostbyname(),
// + inet_common.c has additional IPv4-only stuff
+#define SHA256_INSIZE 64
+#define SHA256_OUTSIZE 32
+#define AES_BLOCKSIZE 16
+#define AES128_KEYSIZE 16
+#define AES256_KEYSIZE 32
+struct tls_handshake_data; /* opaque */
+typedef struct tls_state {
+ int ofd;
+ int ifd;
+
+ int min_encrypted_len_on_read;
+ uint8_t encrypt_on_write;
+
+ uint8_t *outbuf;
+ int outbuf_size;
+
+ int inbuf_size;
+ int ofs_to_buffered;
+ int buffered_size;
+ uint8_t *inbuf;
+
+ struct tls_handshake_data *hsd;
+
+ // RFC 5246
+ // sequence number
+ // Each connection state contains a sequence number, which is
+ // maintained separately for read and write states. The sequence
+ // number MUST be set to zero whenever a connection state is made the
+ // active state. Sequence numbers are of type uint64 and may not
+ // exceed 2^64-1.
+ /*uint64_t read_seq64_be;*/
+ uint64_t write_seq64_be;
+
+ uint8_t client_write_MAC_key[SHA256_OUTSIZE];
+ uint8_t server_write_MAC_key[SHA256_OUTSIZE];
+ uint8_t client_write_key[AES256_KEYSIZE];
+ uint8_t server_write_key[AES256_KEYSIZE];
+} tls_state_t;
+
+static inline tls_state_t *new_tls_state(void)
+{
+ tls_state_t *tls = xzalloc(sizeof(*tls));
+ return tls;
+}
+void tls_handshake(tls_state_t *tls, const char *sni) FAST_FUNC;
+void tls_run_copy_loop(tls_state_t *tls) FAST_FUNC;
void socket_want_pktinfo(int fd) FAST_FUNC;
ssize_t send_to_from(int fd, void *buf, size_t len, int flags,
@@ -705,9 +772,6 @@ ssize_t recv_from_to(int fd, void *buf, size_t len, int flags,
uint16_t inet_cksum(uint16_t *addr, int len) FAST_FUNC;
-char *xstrdup(const char *s) FAST_FUNC RETURNS_MALLOC;
-char *xstrndup(const char *s, int n) FAST_FUNC RETURNS_MALLOC;
-void *xmemdup(const void *s, int n) FAST_FUNC RETURNS_MALLOC;
void overlapping_strcpy(char *dst, const char *src) FAST_FUNC;
char *safe_strncpy(char *dst, const char *src, size_t size) FAST_FUNC;
char *strncpy_IFNAMSIZ(char *dst, const char *src) FAST_FUNC;
@@ -753,24 +817,6 @@ enum {
};
void visible(unsigned ch, char *buf, int flags) FAST_FUNC;
-/* dmalloc will redefine these to it's own implementation. It is safe
- * to have the prototypes here unconditionally. */
-void *malloc_or_warn(size_t size) FAST_FUNC RETURNS_MALLOC;
-void *xmalloc(size_t size) FAST_FUNC RETURNS_MALLOC;
-void *xzalloc(size_t size) FAST_FUNC RETURNS_MALLOC;
-void *xrealloc(void *old, size_t size) FAST_FUNC;
-/* After v = xrealloc_vector(v, SHIFT, idx) it's ok to use
- * at least v[idx] and v[idx+1], for all idx values.
- * SHIFT specifies how many new elements are added (1:2, 2:4, ..., 8:256...)
- * when all elements are used up. New elements are zeroed out.
- * xrealloc_vector(v, SHIFT, idx) *MUST* be called with consecutive IDXs -
- * skipping an index is a bad bug - it may miss a realloc!
- */
-#define xrealloc_vector(vector, shift, idx) \
- xrealloc_vector_helper((vector), (sizeof((vector)[0]) << 8) + (shift), (idx))
-void* xrealloc_vector_helper(void *vector, unsigned sizeof_and_shift, int idx) FAST_FUNC;
-
-
extern ssize_t safe_read(int fd, void *buf, size_t count) FAST_FUNC;
extern ssize_t nonblock_immune_read(int fd, void *buf, size_t count) FAST_FUNC;
// NB: will return short read on error, not -1,
diff --git a/networking/ssl_client.c b/networking/ssl_client.c
new file mode 100644
index 000000000..cfeae1587
--- /dev/null
+++ b/networking/ssl_client.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2017 Denys Vlasenko
+ *
+ * Licensed under GPLv2, see file LICENSE in this source tree.
+ */
+//config:config SSL_CLIENT
+//config: bool "ssl_client"
+//config: default y
+//config: select TLS
+//config: help
+//config: This tool pipes data to/from a socket, TLS-encrypting it.
+
+//applet:IF_SSL_CLIENT(APPLET(ssl_client, BB_DIR_USR_BIN, BB_SUID_DROP))
+
+//kbuild:lib-$(CONFIG_SSL_CLIENT) += ssl_client.o
+
+//usage:#define ssl_client_trivial_usage
+//usage: "-s FD [-r FD] [-n SNI]"
+//usage:#define ssl_client_full_usage ""
+
+#include "libbb.h"
+
+int ssl_client_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int ssl_client_main(int argc UNUSED_PARAM, char **argv)
+{
+ tls_state_t *tls;
+ const char *sni = NULL;
+ int opt;
+
+ // INIT_G();
+
+ tls = new_tls_state();
+ opt = getopt32(argv, "s:#r:#n:", &tls->ofd, &tls->ifd, &sni);
+ if (!(opt & 2)) {
+ /* -r N defaults to -s N */
+ tls->ifd = tls->ofd;
+ }
+
+ if (!(opt & 3)) {
+ if (!argv[1])
+ bb_show_usage();
+ /* Undocumented debug feature: without -s and -r, takes HOST arg and connects to it */
+ //
+ // Talk to kernel.org:
+ // printf "GET / HTTP/1.1\r\nHost: kernel.org\r\n\r\n" | ./busybox ssl_client kernel.org
+ if (!sni)
+ sni = argv[1];
+ tls->ifd = tls->ofd = create_and_connect_stream_or_die(argv[1], 443);
+ }
+
+ tls_handshake(tls, sni);
+ tls_run_copy_loop(tls);
+
+ return EXIT_SUCCESS;
+}
diff --git a/networking/tls.c b/networking/tls.c
index b111e4bb4..29cc5b9f3 100644
--- a/networking/tls.c
+++ b/networking/tls.c
@@ -4,11 +4,9 @@
* Licensed under GPLv2, see file LICENSE in this source tree.
*/
//config:config TLS
-//config: bool "tls (debugging)"
+//config: bool #No description makes it a hidden option
//config: default n
-//applet:IF_TLS(APPLET(tls, BB_DIR_USR_BIN, BB_SUID_DROP))
-
//kbuild:lib-$(CONFIG_TLS) += tls.o
//kbuild:lib-$(CONFIG_TLS) += tls_pstm.o
//kbuild:lib-$(CONFIG_TLS) += tls_pstm_montgomery_reduce.o
@@ -18,12 +16,7 @@
//kbuild:lib-$(CONFIG_TLS) += tls_aes.o
////kbuild:lib-$(CONFIG_TLS) += tls_aes_gcm.o
-//usage:#define tls_trivial_usage
-//usage: "HOST[:PORT]"
-//usage:#define tls_full_usage "\n\n"
-
#include "tls.h"
-//#include "common_bufsiz.h"
#define TLS_DEBUG 1
#define TLS_DEBUG_HASH 0
@@ -165,13 +158,6 @@
#define CIPHER_ID TLS_RSA_WITH_AES_256_CBC_SHA256 // ok, no SERVER_KEY_EXCHANGE
enum {
- SHA256_INSIZE = 64,
- SHA256_OUTSIZE = 32,
-
- AES_BLOCKSIZE = 16,
- AES128_KEYSIZE = 16,
- AES256_KEYSIZE = 32,
-
RSA_PREMASTER_SIZE = 48,
RECHDR_LEN = 5,
@@ -225,20 +211,7 @@ struct record_hdr {
uint8_t len16_hi, len16_lo;
};
-typedef struct tls_state {
- int fd;
-
- int min_encrypted_len_on_read;
- uint8_t encrypt_on_write;
-
- uint8_t *outbuf;
- int outbuf_size;
-
- int inbuf_size;
- int ofs_to_buffered;
- int buffered_size;
- uint8_t *inbuf;
-
+struct tls_handshake_data {
//TODO: store just the DER key here, parse/use/delete it when sending client key
//this way it will stay key type agnostic here.
psRsaKey_t server_rsa_pub_key;
@@ -247,22 +220,7 @@ typedef struct tls_state {
// these two are unused after finished messages are exchanged:
sha256_ctx_t handshake_sha256_ctx;
uint8_t master_secret[48];
-
- // RFC 5246
- // sequence number
- // Each connection state contains a sequence number, which is
- // maintained separately for read and write states. The sequence
- // number MUST be set to zero whenever a connection state is made the
- // active state. Sequence numbers are of type uint64 and may not
- // exceed 2^64-1.
- /*uint64_t read_seq64_be;*/
- uint64_t write_seq64_be;
-
- uint8_t client_write_MAC_key[SHA256_OUTSIZE];
- uint8_t server_write_MAC_key[SHA256_OUTSIZE];
- uint8_t client_write_key[AES256_KEYSIZE];
- uint8_t server_write_key[AES256_KEYSIZE];
-} tls_state_t;
+};
static unsigned get24be(const uint8_t *p)
@@ -487,14 +445,6 @@ static void prf_hmac_sha256(
#undef SEED
}
-static tls_state_t *new_tls_state(void)
-{
- tls_state_t *tls = xzalloc(sizeof(*tls));
- tls->fd = -1;
- sha256_begin(&tls->handshake_sha256_ctx);
- return tls;
-}
-
static void tls_error_die(tls_state_t *tls)
{
dump_tls_record(tls->inbuf, tls->ofs_to_buffered + tls->buffered_size);
@@ -597,7 +547,7 @@ static void xwrite_encrypted(tls_state_t *tls, unsigned size, unsigned type)
xhdr->len16_hi = size >> 8;
xhdr->len16_lo = size & 0xff;
dump_raw_out(">> %s\n", xhdr, RECHDR_LEN + size);
- xwrite(tls->fd, xhdr, RECHDR_LEN + size);
+ xwrite(tls->ofd, xhdr, RECHDR_LEN + size);
dbg("wrote %u bytes (NULL crypt, SHA256 hash)\n", size);
return;
}
@@ -681,7 +631,7 @@ static void xwrite_encrypted(tls_state_t *tls, unsigned size, unsigned type)
xhdr->len16_hi = size >> 8;
xhdr->len16_lo = size & 0xff;
dump_raw_out(">> %s\n", xhdr, RECHDR_LEN + size);
- xwrite(tls->fd, xhdr, RECHDR_LEN + size);
+ xwrite(tls->ofd, xhdr, RECHDR_LEN + size);
dbg("wrote %u bytes\n", (int)RECHDR_LEN + size);
}
@@ -697,10 +647,10 @@ static void xwrite_and_update_handshake_hash(tls_state_t *tls, unsigned size)
xhdr->len16_hi = size >> 8;
xhdr->len16_lo = size & 0xff;
dump_raw_out(">> %s\n", xhdr, RECHDR_LEN + size);
- xwrite(tls->fd, xhdr, RECHDR_LEN + size);
+ xwrite(tls->ofd, xhdr, RECHDR_LEN + size);
dbg("wrote %u bytes\n", (int)RECHDR_LEN + size);
/* Handshake hash does not include record headers */
- sha256_hash_dbg(">> sha256:%s", &tls->handshake_sha256_ctx, buf, size);
+ sha256_hash_dbg(">> sha256:%s", &tls->hsd->handshake_sha256_ctx, buf, size);
return;
}
xwrite_encrypted(tls, size, RECORD_TYPE_HANDSHAKE);
@@ -769,7 +719,7 @@ static int tls_xread_record(tls_state_t *tls)
rem = tls->inbuf_size - total;
tls->inbuf = xrealloc(tls->inbuf, tls->inbuf_size);
}
- sz = safe_read(tls->fd, tls->inbuf + total, rem);
+ sz = safe_read(tls->ifd, tls->inbuf + total, rem);
if (sz <= 0) {
if (sz == 0 && total == 0) {
/* "Abrupt" EOF, no TLS shutdown (seen from kernel.org) */
@@ -848,7 +798,7 @@ static int tls_xread_record(tls_state_t *tls)
* in our FINISHED record must include data of incoming packets too!
*/
if (tls->inbuf[0] == RECORD_TYPE_HANDSHAKE) {
- sha256_hash_dbg("<< sha256:%s", &tls->handshake_sha256_ctx, tls->inbuf + RECHDR_LEN, sz);
+ sha256_hash_dbg("<< sha256:%s", &tls->hsd->handshake_sha256_ctx, tls->inbuf + RECHDR_LEN, sz);
}
end:
dbg("got block len:%u\n", sz);
@@ -1059,12 +1009,12 @@ static void find_key_in_der_cert(tls_state_t *tls, uint8_t *der, int len)
xfunc_die();
der++;
der = enter_der_item(der, &end); /* enter SEQ */
- /* memset(tls->server_rsa_pub_key, 0, sizeof(tls->server_rsa_pub_key)); - already is */
- der_binary_to_pstm(&tls->server_rsa_pub_key.N, der, end); /* modulus */
+ /* memset(tls->hsd->server_rsa_pub_key, 0, sizeof(tls->hsd->server_rsa_pub_key)); - already is */
+ der_binary_to_pstm(&tls->hsd->server_rsa_pub_key.N, der, end); /* modulus */
der = skip_der_item(der, end);
- der_binary_to_pstm(&tls->server_rsa_pub_key.e, der, end); /* exponent */
- tls->server_rsa_pub_key.size = pstm_unsigned_bin_size(&tls->server_rsa_pub_key.N);
- dbg("server_rsa_pub_key.size:%d\n", tls->server_rsa_pub_key.size);
+ der_binary_to_pstm(&tls->hsd->server_rsa_pub_key.e, der, end); /* exponent */
+ tls->hsd->server_rsa_pub_key.size = pstm_unsigned_bin_size(&tls->hsd->server_rsa_pub_key.N);
+ dbg("server_rsa_pub_key.size:%d\n", tls->hsd->server_rsa_pub_key.size);
}
/*
@@ -1140,7 +1090,7 @@ static void send_client_hello(tls_state_t *tls, const char *sni)
tls_get_random(record->rand32, sizeof(record->rand32));
if (TLS_DEBUG_FIXED_SECRETS)
memset(record->rand32, 0x11, sizeof(record->rand32));
- memcpy(tls->client_and_server_rand32, record->rand32, sizeof(record->rand32));
+ memcpy(tls->hsd->client_and_server_rand32, record->rand32, sizeof(record->rand32));
/* record->session_id_len = 0; - already is */
/* record->cipherid_len16_hi = 0; */
record->cipherid_len16_lo = 2 * 1;
@@ -1225,7 +1175,7 @@ static void get_server_hello(tls_state_t *tls)
}
dbg("<< SERVER_HELLO\n");
- memcpy(tls->client_and_server_rand32 + 32, hp->rand32, sizeof(hp->rand32));
+ memcpy(tls->hsd->client_and_server_rand32 + 32, hp->rand32, sizeof(hp->rand32));
}
static void get_server_cert(tls_state_t *tls)
@@ -1282,7 +1232,7 @@ static void send_client_key_exchange(tls_state_t *tls)
rsa_premaster[0] = TLS_MAJ;
rsa_premaster[1] = TLS_MIN;
len = psRsaEncryptPub(/*pool:*/ NULL,
- /* psRsaKey_t* */ &tls->server_rsa_pub_key,
+ /* psRsaKey_t* */ &tls->hsd->server_rsa_pub_key,
rsa_premaster, /*inlen:*/ sizeof(rsa_premaster),
record->key, sizeof(record->key),
data_param_ignored
@@ -1310,12 +1260,12 @@ static void send_client_key_exchange(tls_state_t *tls)
// The master secret is always exactly 48 bytes in length. The length
// of the premaster secret will vary depending on key exchange method.
prf_hmac_sha256(
- tls->master_secret, sizeof(tls->master_secret),
+ tls->hsd->master_secret, sizeof(tls->hsd->master_secret),
rsa_premaster, sizeof(rsa_premaster),
"master secret",
- tls->client_and_server_rand32, sizeof(tls->client_and_server_rand32)
+ tls->hsd->client_and_server_rand32, sizeof(tls->hsd->client_and_server_rand32)
);
- dump_hex("master secret:%s\n", tls->master_secret, sizeof(tls->master_secret));
+ dump_hex("master secret:%s\n", tls->hsd->master_secret, sizeof(tls->hsd->master_secret));
// RFC 5246
// 6.3. Key Calculation
@@ -1354,8 +1304,8 @@ static void send_client_key_exchange(tls_state_t *tls)
uint8_t tmp64[64];
/* make "server_rand32 + client_rand32" */
- memcpy(&tmp64[0] , &tls->client_and_server_rand32[32], 32);
- memcpy(&tmp64[32], &tls->client_and_server_rand32[0] , 32);
+ memcpy(&tmp64[0] , &tls->hsd->client_and_server_rand32[32], 32);
+ memcpy(&tmp64[32], &tls->hsd->client_and_server_rand32[0] , 32);
prf_hmac_sha256(
tls->client_write_MAC_key, 2 * (SHA256_OUTSIZE + AES256_KEYSIZE),
@@ -1363,7 +1313,7 @@ static void send_client_key_exchange(tls_state_t *tls)
// server_write_MAC_key[SHA256_OUTSIZE]
// client_write_key[AES256_KEYSIZE]
// server_write_key[AES256_KEYSIZE]
- tls->master_secret, sizeof(tls->master_secret),
+ tls->hsd->master_secret, sizeof(tls->hsd->master_secret),
"key expansion",
tmp64, 64
);
@@ -1384,7 +1334,7 @@ static const uint8_t rec_CHANGE_CIPHER_SPEC[] = {
static void send_change_cipher_spec(tls_state_t *tls)
{
dbg(">> CHANGE_CIPHER_SPEC\n");
- xwrite(tls->fd, rec_CHANGE_CIPHER_SPEC, sizeof(rec_CHANGE_CIPHER_SPEC));
+ xwrite(tls->ofd, rec_CHANGE_CIPHER_SPEC, sizeof(rec_CHANGE_CIPHER_SPEC));
}
// 7.4.9. Finished
@@ -1436,13 +1386,13 @@ static void send_client_finished(tls_state_t *tls)
fill_handshake_record_hdr(record, HANDSHAKE_FINISHED, sizeof(*record));
- sha256_peek(&tls->handshake_sha256_ctx, handshake_hash);
+ sha256_peek(&tls->hsd->handshake_sha256_ctx, handshake_hash);
prf_hmac_sha256(record->prf_result, sizeof(record->prf_result),
- tls->master_secret, sizeof(tls->master_secret),
+ tls->hsd->master_secret, sizeof(tls->hsd->master_secret),
"client finished",
handshake_hash, sizeof(handshake_hash)
);
- dump_hex("from secret: %s\n", tls->master_secret, sizeof(tls->master_secret));
+ dump_hex("from secret: %s\n", tls->hsd->master_secret, sizeof(tls->hsd->master_secret));
dump_hex("from labelSeed: %s", "client finished", sizeof("client finished")-1);
dump_hex("%s\n", handshake_hash, sizeof(handshake_hash));
dump_hex("=> digest: %s\n", record->prf_result, sizeof(record->prf_result));
@@ -1451,7 +1401,7 @@ static void send_client_finished(tls_state_t *tls)
xwrite_encrypted(tls, sizeof(*record), RECORD_TYPE_HANDSHAKE);
}
-static void tls_handshake(tls_state_t *tls, const char *sni)
+void FAST_FUNC tls_handshake(tls_state_t *tls, const char *sni)
{
// Client RFC 5246 Server
// (*) - optional messages, not always sent
@@ -1472,6 +1422,9 @@ static void tls_handshake(tls_state_t *tls, const char *sni)
// Application Data <------> Application Data
int len;
+ tls->hsd = xzalloc(sizeof(*tls->hsd));
+ sha256_begin(&tls->hsd->handshake_sha256_ctx);
+
send_client_hello(tls, sni);
get_server_hello(tls);
@@ -1541,6 +1494,12 @@ static void tls_handshake(tls_state_t *tls, const char *sni)
tls_error_die(tls);
dbg("<< FINISHED\n");
/* application data can be sent/received */
+
+ /* free handshake data */
+// if (PARANOIA)
+// memset(tls->hsd, 0, sizeof(*tls->hsd));
+ free(tls->hsd);
+ tls->hsd = NULL;
}
static void tls_xwrite(tls_state_t *tls, int len)
@@ -1557,35 +1516,17 @@ static void tls_xwrite(tls_state_t *tls, int len)
// openssl req -x509 -newkey rsa:$((4096/4*3)) -keyout key.pem -out server.pem -nodes -days 99999 -subj '/CN=localhost'
// openssl s_server -key key.pem -cert server.pem -debug -tls1_2 -no_tls1 -no_tls1_1 -cipher NULL
// openssl s_client -connect 127.0.0.1:4433 -debug -tls1_2 -no_tls1 -no_tls1_1 -cipher NULL-SHA256
-//
-// Talk to kernel.org:
-// printf "GET / HTTP/1.1\r\nHost: kernel.org\r\n\r\n" | ./busybox tls kernel.org
-int tls_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
-int tls_main(int argc UNUSED_PARAM, char **argv)
+void FAST_FUNC tls_run_copy_loop(tls_state_t *tls)
{
- tls_state_t *tls;
fd_set readfds;
int inbuf_size;
const int INBUF_STEP = 4 * 1024;
- int cfd;
-
- // INIT_G();
- // getopt32(argv, "myopts")
-
- if (!argv[1])
- bb_show_usage();
-
- cfd = create_and_connect_stream_or_die(argv[1], 443);
-
- tls = new_tls_state();
- tls->fd = cfd;
- tls_handshake(tls, argv[1]);
-
- /* Select loop copying stdin to cfd, and cfd to stdout */
+//TODO: convert to poll
+ /* Select loop copying stdin to ofd, and ifd to stdout */
FD_ZERO(&readfds);
- FD_SET(cfd, &readfds);
+ FD_SET(tls->ifd, &readfds);
FD_SET(STDIN_FILENO, &readfds);
inbuf_size = INBUF_STEP;
@@ -1594,7 +1535,7 @@ int tls_main(int argc UNUSED_PARAM, char **argv)
int nread;
testfds = readfds;
- if (select(cfd + 1, &testfds, NULL, NULL, NULL) < 0)
+ if (select(tls->ifd + 1, &testfds, NULL, NULL, NULL) < 0)
bb_perror_msg_and_die("select");
if (FD_ISSET(STDIN_FILENO, &testfds)) {
@@ -1608,7 +1549,7 @@ int tls_main(int argc UNUSED_PARAM, char **argv)
/* Close outgoing half-connection so they get EOF,
* but leave incoming alone so we can see response
*/
- //shutdown(cfd, SHUT_WR);
+ //shutdown(tls->ofd, SHUT_WR);
/* But TLS has no way to encode this,
* doubt it's ok to do it "raw"
*/
@@ -1626,7 +1567,7 @@ int tls_main(int argc UNUSED_PARAM, char **argv)
tls_xwrite(tls, nread);
}
}
- if (FD_ISSET(cfd, &testfds)) {
+ if (FD_ISSET(tls->ifd, &testfds)) {
dbg("NETWORK HAS DATA\n");
read_record:
nread = tls_xread_record(tls);
@@ -1634,7 +1575,7 @@ int tls_main(int argc UNUSED_PARAM, char **argv)
/* TLS protocol has no real concept of one-sided shutdowns:
* if we get "TLS EOF" from the peer, writes will fail too
*/
- //FD_CLR(cfd, &readfds);
+ //FD_CLR(tls->ifd, &readfds);
//close(STDOUT_FILENO);
//tls_free_inbuf(tls); /* mem usage optimization */
//continue;
@@ -1650,6 +1591,4 @@ int tls_main(int argc UNUSED_PARAM, char **argv)
goto read_record;
}
}
-
- return EXIT_SUCCESS;
}
diff --git a/networking/wget.c b/networking/wget.c
index 58ead4c96..a448acdae 100644
--- a/networking/wget.c
+++ b/networking/wget.c
@@ -47,18 +47,26 @@
//config: FEATURE_WGET_LONG_OPTIONS is also enabled, the --timeout option
//config: will work in addition to -T.
//config:
+//config:config FEATURE_WGET_HTTPS
+//config: bool "Support HTTPS using internal TLS code"
+//config: default y
+//config: depends on WGET
+//config: select TLS
+//config: help
+//config: wget will use internal TLS code to connect to https:// URLs.
+//config: Note:
+//config: On NOMMU machines, ssl_helper applet should be available
+//config: in the $PATH for this to work. Make sure to select that applet.
+//config:
//config:config FEATURE_WGET_OPENSSL
//config: bool "Try to connect to HTTPS using openssl"
//config: default y
//config: depends on WGET
//config: help
-//config: Choose how wget establishes SSL connection for https:// URLs.
-//config:
-//config: Busybox itself contains no SSL code. wget will spawn
-//config: a helper program to talk over HTTPS.
+//config: Try to use openssl to handle HTTPS.
//config:
//config: OpenSSL has a simple SSL client for debug purposes.
-//config: If you select "openssl" helper, wget will effectively run:
+//config: If you select this option, wget will effectively run:
//config: "openssl s_client -quiet -connect hostname:443
//config: -servername hostname 2>/dev/null" and pipe its data
//config: through it. -servername is not used if hostname is numeric.
@@ -71,24 +79,9 @@
//config: openssl is also a big binary, often dynamically linked
//config: against ~15 libraries.
//config:
-//config:config FEATURE_WGET_SSL_HELPER
-//config: bool "Try to connect to HTTPS using ssl_helper"
-//config: default y
-//config: depends on WGET
-//config: help
-//config: Choose how wget establishes SSL connection for https:// URLs.
-//config:
-//config: Busybox itself contains no SSL code. wget will spawn
-//config: a helper program to talk over HTTPS.
-//config:
-//config: ssl_helper is a tool which can be built statically
-//config: from busybox sources against a small embedded SSL library.
-//config: Please see networking/ssl_helper/README.
-//config: It does not require double host resolution and emits
-//config: error messages to stderr.
-//config:
-//config: Precompiled static binary may be available at
-//config: http://busybox.net/downloads/binaries/
+//config: If openssl can't be executed, internal TLS code will be used
+//config: (if you enabled it); if openssl can be executed but fails later,
+//config: wget can't detect this, and download will fail.
//applet:IF_WGET(APPLET(wget, BB_DIR_USR_BIN, BB_SUID_DROP))
@@ -137,7 +130,7 @@
#endif
-#define SSL_SUPPORTED (ENABLE_FEATURE_WGET_OPENSSL || ENABLE_FEATURE_WGET_SSL_HELPER)
+#define SSL_SUPPORTED (ENABLE_FEATURE_WGET_OPENSSL || ENABLE_FEATURE_WGET_HTTPS)
struct host_info {
char *allocated;
@@ -657,7 +650,7 @@ static int spawn_https_helper_openssl(const char *host, unsigned port)
char *servername;
int sp[2];
int pid;
- IF_FEATURE_WGET_SSL_HELPER(volatile int child_failed = 0;)
+ IF_FEATURE_WGET_HTTPS(volatile int child_failed = 0;)
if (socketpair(AF_UNIX, SOCK_STREAM, 0, sp) != 0)
/* Kernel can have AF_UNIX support disabled */
@@ -702,7 +695,7 @@ static int spawn_https_helper_openssl(const char *host, unsigned port)
BB_EXECVP(argv[0], argv);
xmove_fd(3, 2);
-# if ENABLE_FEATURE_WGET_SSL_HELPER
+# if ENABLE_FEATURE_WGET_HTTPS
child_failed = 1;
xfunc_die();
# else
@@ -715,7 +708,7 @@ static int spawn_https_helper_openssl(const char *host, unsigned port)
free(servername);
free(allocated);
close(sp[1]);
-# if ENABLE_FEATURE_WGET_SSL_HELPER
+# if ENABLE_FEATURE_WGET_HTTPS
if (child_failed) {
close(sp[0]);
return -1;
@@ -725,38 +718,51 @@ static int spawn_https_helper_openssl(const char *host, unsigned port)
}
#endif
-/* See networking/ssl_helper/README how to build one */
-#if ENABLE_FEATURE_WGET_SSL_HELPER
-static void spawn_https_helper_small(int network_fd)
+#if ENABLE_FEATURE_WGET_HTTPS
+static void spawn_ssl_client(const char *host, int network_fd)
{
int sp[2];
int pid;
+ char *servername, *p;
+
+ servername = xstrdup(host);
+ p = strrchr(servername, ':');
+ if (p) *p = '\0';
if (socketpair(AF_UNIX, SOCK_STREAM, 0, sp) != 0)
/* Kernel can have AF_UNIX support disabled */
bb_perror_msg_and_die("socketpair");
+ fflush_all();
pid = BB_MMU ? xfork() : xvfork();
if (pid == 0) {
/* Child */
- char *argv[3];
-
close(sp[0]);
xmove_fd(sp[1], 0);
xdup2(0, 1);
- xmove_fd(network_fd, 3);
- /*
- * A simple ssl/tls helper
- */
- argv[0] = (char*)"ssl_helper";
- argv[1] = (char*)"-d3";
- argv[2] = NULL;
- BB_EXECVP(argv[0], argv);
- bb_perror_msg_and_die("can't execute '%s'", argv[0]);
+ if (BB_MMU) {
+ tls_state_t *tls = new_tls_state();
+ tls->ifd = tls->ofd = network_fd;
+ tls_handshake(tls, servername);
+ tls_run_copy_loop(tls);
+ exit(0);
+ } else {
+ char *argv[5];
+ xmove_fd(network_fd, 3);
+ argv[0] = (char*)"ssl_client";
+ argv[1] = (char*)"-s3";
+ //TODO: if (!is_ip_address(servername))...
+ argv[2] = (char*)"-n";
+ argv[3] = servername;
+ argv[4] = NULL;
+ BB_EXECVP(argv[0], argv);
+ bb_perror_msg_and_die("can't execute '%s'", argv[0]);
+ }
/* notreached */
}
/* Parent */
+ free(servername);
close(sp[1]);
xmove_fd(sp[0], network_fd);
}
@@ -1005,16 +1011,16 @@ static void download_one_url(const char *url)
/* Open socket to http(s) server */
#if ENABLE_FEATURE_WGET_OPENSSL
- /* openssl (and maybe ssl_helper) support is configured */
+ /* openssl (and maybe internal TLS) support is configured */
if (target.protocol == P_HTTPS) {
/* openssl-based helper
* Inconvenient API since we can't give it an open fd
*/
int fd = spawn_https_helper_openssl(server.host, server.port);
-# if ENABLE_FEATURE_WGET_SSL_HELPER
- if (fd < 0) { /* no openssl? try ssl_helper */
+# if ENABLE_FEATURE_WGET_HTTPS
+ if (fd < 0) { /* no openssl? try internal */
sfp = open_socket(lsa);
- spawn_https_helper_small(fileno(sfp));
+ spawn_ssl_client(server.host, fileno(sfp));
goto socket_opened;
}
# else
@@ -1027,11 +1033,11 @@ static void download_one_url(const char *url)
}
sfp = open_socket(lsa);
socket_opened:
-#elif ENABLE_FEATURE_WGET_SSL_HELPER
- /* Only ssl_helper support is configured */
+#elif ENABLE_FEATURE_WGET_HTTPS
+ /* Only internal TLS support is configured */
sfp = open_socket(lsa);
if (target.protocol == P_HTTPS)
- spawn_https_helper_small(fileno(sfp));
+ spawn_ssl_client(server.host, fileno(sfp));
#else
/* ssl (https) support is not configured */
sfp = open_socket(lsa);