summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTimotej S <6674623+underhood@users.noreply.github.com>2022-12-21 08:29:18 +0700
committerGitHub <noreply@github.com>2022-12-21 08:29:18 +0700
commit474d80ef10c8476c210a5018a3f5c6edcf2d899d (patch)
treedc1a0b7862f94611b12a35f69b8b3afd0fd672c9
parent0804995b0e45575411c860d243ded865cfbb1a16 (diff)
Support HTTP proxy Basic auth (#13762)
-rw-r--r--aclk/aclk.c7
-rw-r--r--aclk/aclk_otp.c25
-rw-r--r--aclk/aclk_util.c102
-rw-r--r--aclk/aclk_util.h4
-rw-r--r--aclk/https_client.c22
-rw-r--r--aclk/https_client.h2
6 files changed, 125 insertions, 37 deletions
diff --git a/aclk/aclk.c b/aclk/aclk.c
index 45f3bb4760..c3d0fc891e 100644
--- a/aclk/aclk.c
+++ b/aclk/aclk.c
@@ -532,7 +532,7 @@ static int aclk_attempt_to_connect(mqtt_wss_client client)
}
struct mqtt_wss_proxy proxy_conf = { .host = NULL, .port = 0, .username = NULL, .password = NULL, .type = MQTT_WSS_DIRECT };
- aclk_set_proxy((char**)&proxy_conf.host, &proxy_conf.port, &proxy_conf.type);
+ aclk_set_proxy((char**)&proxy_conf.host, &proxy_conf.port, (char**)&proxy_conf.username, (char**)&proxy_conf.password, &proxy_conf.type);
struct mqtt_connect_params mqtt_conn_params = {
.clientid = "anon",
@@ -630,7 +630,10 @@ static int aclk_attempt_to_connect(mqtt_wss_client client)
freez((char*)mqtt_conn_params.username);
#endif
- freez((char *)mqtt_conn_params.will_msg);
+ freez((char*)mqtt_conn_params.will_msg);
+ freez((char*)proxy_conf.host);
+ freez((char*)proxy_conf.username);
+ freez((char*)proxy_conf.password);
if (!ret) {
last_conn_time_mqtt = now_realtime_sec();
diff --git a/aclk/aclk_otp.c b/aclk/aclk_otp.c
index 2bdbb70fb1..940d5bdbe5 100644
--- a/aclk/aclk_otp.c
+++ b/aclk/aclk_otp.c
@@ -14,15 +14,19 @@ static int aclk_https_request(https_req_t *request, https_req_response_t *respon
// wrapper for ACLK only which loads ACLK specific proxy settings
// then only calls https_request
struct mqtt_wss_proxy proxy_conf = { .host = NULL, .port = 0, .username = NULL, .password = NULL, .type = MQTT_WSS_DIRECT };
- aclk_set_proxy((char**)&proxy_conf.host, &proxy_conf.port, &proxy_conf.type);
+ aclk_set_proxy((char**)&proxy_conf.host, &proxy_conf.port, (char**)&proxy_conf.username, (char**)&proxy_conf.password, &proxy_conf.type);
if (proxy_conf.type == MQTT_WSS_PROXY_HTTP) {
request->proxy_host = (char*)proxy_conf.host; // TODO make it const as well
request->proxy_port = proxy_conf.port;
+ request->proxy_username = proxy_conf.username;
+ request->proxy_password = proxy_conf.password;
}
rc = https_request(request, response);
freez((char*)proxy_conf.host);
+ freez((char*)proxy_conf.username);
+ freez((char*)proxy_conf.password);
return rc;
}
@@ -303,25 +307,6 @@ inline static int base64_decode_helper(unsigned char *out, int *outl, const unsi
return 0;
}
-inline static int base64_encode_helper(unsigned char *out, int *outl, const unsigned char *in, int in_len)
-{
- int len;
- unsigned char *str = out;
- EVP_ENCODE_CTX *ctx = EVP_ENCODE_CTX_new();
- EVP_EncodeInit(ctx);
- EVP_EncodeUpdate(ctx, str, outl, in, in_len);
- str += *outl;
- EVP_EncodeFinal(ctx, str, &len);
- *outl += len;
- // if we ever expect longer output than what OpenSSL would pack into single line
- // we would have to skip the endlines, until then we can just cut the string short
- str = (unsigned char*)strchr((char*)out, '\n');
- if (str)
- *str = 0;
- EVP_ENCODE_CTX_free(ctx);
- return 0;
-}
-
#define OTP_URL_PREFIX "/api/v1/auth/node/"
int aclk_get_otp_challenge(url_t *target, const char *agent_id, unsigned char **challenge, int *challenge_bytes)
{
diff --git a/aclk/aclk_util.c b/aclk/aclk_util.c
index 01eaedc8e0..27d536e75e 100644
--- a/aclk/aclk_util.c
+++ b/aclk/aclk_util.c
@@ -346,43 +346,117 @@ unsigned long int aclk_tbeb_delay(int reset, int base, unsigned long int min, un
return delay;
}
+static inline int aclk_parse_pair(const char *src, const char c, char **a, char **b)
+{
+ const char *ptr = strchr(src, c);
+ if (ptr == NULL)
+ return 1;
+
+// allow empty string
+/* if (!*(ptr+1))
+ return 1;*/
+
+ *a = callocz(1, ptr - src + 1);
+ memcpy (*a, src, ptr - src);
+
+ *b = strdupz(ptr+1);
+
+ return 0;
+}
#define HTTP_PROXY_PREFIX "http://"
-void aclk_set_proxy(char **ohost, int *port, enum mqtt_wss_proxy_type *type)
+void aclk_set_proxy(char **ohost, int *port, char **uname, char **pwd, enum mqtt_wss_proxy_type *type)
{
ACLK_PROXY_TYPE pt;
const char *ptr = aclk_get_proxy(&pt);
char *tmp;
- char *host;
+
if (pt != PROXY_TYPE_HTTP)
return;
+ *uname = NULL;
+ *pwd = NULL;
*port = 0;
+ char *proxy = strdupz(ptr);
+ ptr = proxy;
+
if (!strncmp(ptr, HTTP_PROXY_PREFIX, strlen(HTTP_PROXY_PREFIX)))
ptr += strlen(HTTP_PROXY_PREFIX);
- if ((tmp = strchr(ptr, '@')))
- ptr = tmp;
+ if ((tmp = strchr(ptr, '@'))) {
+ *tmp = 0;
+ if(aclk_parse_pair(ptr, ':', uname, pwd)) {
+ error_report("Failed to get username and password for proxy. Will attempt connection without authentication");
+ }
+ ptr = tmp+1;
+ }
- if ((tmp = strchr(ptr, '/'))) {
- host = mallocz((tmp - ptr) + 1);
- memcpy(host, ptr, (tmp - ptr));
- host[tmp - ptr] = 0;
- } else
- host = strdupz(ptr);
+ if (!*ptr) {
+ freez(proxy);
+ freez(*uname);
+ freez(*pwd);
+ return;
+ }
- if ((tmp = strchr(host, ':'))) {
+ if ((tmp = strchr(ptr, ':'))) {
*tmp = 0;
tmp++;
- *port = atoi(tmp);
+ if(*tmp)
+ *port = atoi(tmp);
}
+ *ohost = strdupz(ptr);
if (*port <= 0 || *port > 65535)
*port = 8080;
- *ohost = host;
-
if (type)
*type = MQTT_WSS_PROXY_HTTP;
+ else {
+ freez(*uname);
+ freez(*pwd);
+ }
+
+ freez(proxy);
+}
+
+#if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_110
+static EVP_ENCODE_CTX *EVP_ENCODE_CTX_new(void)
+{
+ EVP_ENCODE_CTX *ctx = OPENSSL_malloc(sizeof(*ctx));
+
+ if (ctx != NULL) {
+ memset(ctx, 0, sizeof(*ctx));
+ }
+ return ctx;
+}
+static void EVP_ENCODE_CTX_free(EVP_ENCODE_CTX *ctx)
+{
+ OPENSSL_free(ctx);
+ return;
+}
+#endif
+
+int base64_encode_helper(unsigned char *out, int *outl, const unsigned char *in, int in_len)
+{
+ int len;
+ unsigned char *str = out;
+ EVP_ENCODE_CTX *ctx = EVP_ENCODE_CTX_new();
+ EVP_EncodeInit(ctx);
+ EVP_EncodeUpdate(ctx, str, outl, in, in_len);
+ str += *outl;
+ EVP_EncodeFinal(ctx, str, &len);
+ *outl += len;
+
+ str = out;
+ while(*str) {
+ if (*str != 0x0D && *str != 0x0A)
+ *out++ = *str++;
+ else
+ str++;
+ }
+ *out = 0;
+
+ EVP_ENCODE_CTX_free(ctx);
+ return 0;
}
diff --git a/aclk/aclk_util.h b/aclk/aclk_util.h
index ed715e0466..6a9acbc6ae 100644
--- a/aclk/aclk_util.h
+++ b/aclk/aclk_util.h
@@ -107,6 +107,8 @@ extern volatile int aclk_conversation_log_counter;
unsigned long int aclk_tbeb_delay(int reset, int base, unsigned long int min, unsigned long int max);
#define aclk_tbeb_reset(x) aclk_tbeb_delay(1, 0, 0, 0)
-void aclk_set_proxy(char **ohost, int *port, enum mqtt_wss_proxy_type *type);
+void aclk_set_proxy(char **ohost, int *port, char **uname, char **pwd, enum mqtt_wss_proxy_type *type);
+
+int base64_encode_helper(unsigned char *out, int *outl, const unsigned char *in, int in_len);
#endif /* ACLK_UTIL_H */
diff --git a/aclk/https_client.c b/aclk/https_client.c
index 1a32f833ff..8af85f8546 100644
--- a/aclk/https_client.c
+++ b/aclk/https_client.c
@@ -6,6 +6,8 @@
#include "mqtt_websockets/c-rbuf/include/ringbuffer.h"
+#include "aclk_util.h"
+
enum http_parse_state {
HTTP_PARSE_INITIAL = 0,
HTTP_PARSE_HEADERS,
@@ -392,6 +394,24 @@ static int handle_http_request(https_req_ctx_t *ctx) {
if (ctx->request->request_type == HTTP_REQ_POST && ctx->request->payload && ctx->request->payload_size) {
buffer_sprintf(hdr, "Content-Length: %zu\x0D\x0A", ctx->request->payload_size);
}
+ if (ctx->request->proxy_username) {
+ size_t creds_plain_len = strlen(ctx->request->proxy_username) + strlen(ctx->request->proxy_password) + 1 /* ':' */;
+ char *creds_plain = callocz(1, creds_plain_len + 1);
+ char *ptr = creds_plain;
+ strcpy(ptr, ctx->request->proxy_username);
+ ptr += strlen(ctx->request->proxy_username);
+ *ptr++ = ':';
+ strcpy(ptr, ctx->request->proxy_password);
+
+ int creds_base64_len = (((4 * creds_plain_len / 3) + 3) & ~3);
+ // OpenSSL encoder puts newline every 64 output bytes
+ // we remove those but during encoding we need that space in the buffer
+ creds_base64_len += (1+(creds_base64_len/64)) * strlen("\n");
+ char *creds_base64 = callocz(1, creds_base64_len + 1);
+ base64_encode_helper((unsigned char*)creds_base64, &creds_base64_len, (unsigned char*)creds_plain, creds_plain_len);
+ buffer_sprintf(hdr, "Proxy-Authorization: Basic %s\x0D\x0A", creds_base64);
+ freez(creds_plain);
+ }
buffer_strcat(hdr, "\x0D\x0A");
@@ -491,6 +511,8 @@ int https_request(https_req_t *request, https_req_response_t *response) {
req.host = request->host;
req.port = request->port;
req.url = request->url;
+ req.proxy_username = request->proxy_username;
+ req.proxy_password = request->proxy_password;
ctx->request = &req;
if (handle_http_request(ctx)) {
error("Failed to CONNECT with proxy");
diff --git a/aclk/https_client.h b/aclk/https_client.h
index f7bc3d43d6..daf4766f87 100644
--- a/aclk/https_client.h
+++ b/aclk/https_client.h
@@ -25,6 +25,8 @@ typedef struct {
char *proxy_host;
int proxy_port;
+ const char *proxy_username;
+ const char *proxy_password;
} https_req_t;
typedef struct {