|
|
|
@ -19,15 +19,19 @@
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* this is now the source code for a minimal http client....probably something
|
|
|
|
|
* to do with libabyss -despair
|
|
|
|
|
* see bootstrap.c for the lokinet bootstrap client
|
|
|
|
|
*/
|
|
|
|
|
* to do with libabyss -despair
|
|
|
|
|
* see bootstrap.c for the lokinet bootstrap client
|
|
|
|
|
*
|
|
|
|
|
* This file is part of libuNR.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <stdbool.h>
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
|
#include <windows.h>
|
|
|
|
|
#include <wincrypt.h>
|
|
|
|
|
#endif
|
|
|
|
|
#include "miniz.h"
|
|
|
|
|
|
|
|
|
|
/* PolarSSL */
|
|
|
|
@ -49,7 +53,11 @@ mbedtls_x509_crt cacert;
|
|
|
|
|
unsigned char* ca_certs;
|
|
|
|
|
|
|
|
|
|
/* imageboard ref just because */
|
|
|
|
|
static char userAgent[] = "NetRunner_Micro/0.1 PolarSSL/2.13.0;U;Windows NT ";
|
|
|
|
|
#ifndef _WIN32
|
|
|
|
|
static char userAgent[] = "NetRunner_Micro/0.1 PolarSSL/2.16.0;U;";
|
|
|
|
|
#else
|
|
|
|
|
static char userAgent[] = "NetRunner_Micro/0.1 PolarSSL/2.16.0;U;Windows NT ";
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/* netscape ca bundle */
|
|
|
|
|
static const unsigned char ca_cert_store_encoded[] =
|
|
|
|
@ -2198,89 +2206,182 @@ static const unsigned char ca_cert_store_encoded[] =
|
|
|
|
|
"pqLPvscxpRcQeVwScZEM7ejGcLtfoecWYaHx+nSHDilOO8UVeX81jha9ckJrgIaUEen99unjsCSN"
|
|
|
|
|
"vNycvRG7E2hCmn1FjzkK37f8UhIsyBZNtyX2X3sl/29r4Xgw";
|
|
|
|
|
|
|
|
|
|
typedef struct url_parser_url
|
|
|
|
|
typedef struct url_parser_url
|
|
|
|
|
{
|
|
|
|
|
char *protocol;
|
|
|
|
|
char *host;
|
|
|
|
|
int port;
|
|
|
|
|
char *path;
|
|
|
|
|
char *query_string;
|
|
|
|
|
int host_exists;
|
|
|
|
|
char *host_ip;
|
|
|
|
|
char *protocol;
|
|
|
|
|
char *host;
|
|
|
|
|
int port;
|
|
|
|
|
char *path;
|
|
|
|
|
char *query_string;
|
|
|
|
|
int host_exists;
|
|
|
|
|
char *host_ip;
|
|
|
|
|
} url_parser_url_t;
|
|
|
|
|
|
|
|
|
|
bool initTLS()
|
|
|
|
|
static char seed[64];
|
|
|
|
|
|
|
|
|
|
#ifndef _WIN32
|
|
|
|
|
static
|
|
|
|
|
try_close(fd)
|
|
|
|
|
{
|
|
|
|
|
int ret;
|
|
|
|
|
for(;;)
|
|
|
|
|
{
|
|
|
|
|
errno = 0;
|
|
|
|
|
ret = close(fd);
|
|
|
|
|
if(ret == -1 && errno == EINTR)
|
|
|
|
|
continue;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static
|
|
|
|
|
try_read(fd, out, count)
|
|
|
|
|
char* out;
|
|
|
|
|
size_t count;
|
|
|
|
|
{
|
|
|
|
|
size_t total;
|
|
|
|
|
ssize_t partial;
|
|
|
|
|
|
|
|
|
|
total = 0;
|
|
|
|
|
while(total < count)
|
|
|
|
|
{
|
|
|
|
|
for(;;)
|
|
|
|
|
{
|
|
|
|
|
errno = 0;
|
|
|
|
|
partial = read(fd, out + total, count - total);
|
|
|
|
|
if(partial == -1 && errno == EINTR)
|
|
|
|
|
continue;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(partial < 1)
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
total += partial;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
get_noise()
|
|
|
|
|
{
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
|
HCRYPTPROV hprovider;
|
|
|
|
|
/* On Windows NT 4.0 or later, use CryptoAPI to grab 64 bytes of random data
|
|
|
|
|
*/
|
|
|
|
|
hprovider = 0;
|
|
|
|
|
CryptAcquireContext(&hprovider, NULL, NULL, PROV_RSA_FULL,
|
|
|
|
|
CRYPT_VERIFYCONTEXT | CRYPT_SILENT);
|
|
|
|
|
CryptGenRandom(hprovider, 64, (BYTE *)&seed);
|
|
|
|
|
CryptReleaseContext(hprovider, 0);
|
|
|
|
|
#else
|
|
|
|
|
int fd;
|
|
|
|
|
fd = open("/dev/urandom", O_RDONLY);
|
|
|
|
|
if(fd == -1)
|
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
|
|
if(try_read(fd, seed, 64) != 0)
|
|
|
|
|
{
|
|
|
|
|
if(try_close(fd) != 0)
|
|
|
|
|
goto fail;
|
|
|
|
|
goto fail;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(try_close(fd) != 0)
|
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
|
|
fail:
|
|
|
|
|
printf("failed to read /dev/urandom!\n");
|
|
|
|
|
return false;
|
|
|
|
|
#endif
|
|
|
|
|
int r;
|
|
|
|
|
|
|
|
|
|
seed[63] = '\0'; /* null-terminate for safety */
|
|
|
|
|
|
|
|
|
|
r = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
|
|
|
|
|
(const unsigned char *)seed, 64);
|
|
|
|
|
if(r)
|
|
|
|
|
{
|
|
|
|
|
printf("Error: failed to seed internal RNG!\n");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
initTLS()
|
|
|
|
|
{
|
|
|
|
|
int inf_status,r;
|
|
|
|
|
size_t out;
|
|
|
|
|
unsigned long inf_len;
|
|
|
|
|
HCRYPTPROV hprovider;
|
|
|
|
|
unsigned char* tmp;
|
|
|
|
|
char str[512], seed[64];
|
|
|
|
|
int inf_status, r;
|
|
|
|
|
size_t out;
|
|
|
|
|
unsigned long inf_len;
|
|
|
|
|
unsigned char *tmp;
|
|
|
|
|
char str[512];
|
|
|
|
|
|
|
|
|
|
mbedtls_net_init(&server_fd);
|
|
|
|
|
mbedtls_ssl_init(&ssl);
|
|
|
|
|
mbedtls_ssl_config_init(&conf);
|
|
|
|
|
mbedtls_x509_crt_init(&cacert);
|
|
|
|
|
mbedtls_entropy_init(&entropy);
|
|
|
|
|
mbedtls_ctr_drbg_init(&ctr_drbg);
|
|
|
|
|
mbedtls_net_init(&server_fd);
|
|
|
|
|
mbedtls_ssl_init(&ssl);
|
|
|
|
|
mbedtls_ssl_config_init(&conf);
|
|
|
|
|
mbedtls_x509_crt_init(&cacert);
|
|
|
|
|
mbedtls_entropy_init(&entropy);
|
|
|
|
|
mbedtls_ctr_drbg_init(&ctr_drbg);
|
|
|
|
|
|
|
|
|
|
tmp = malloc(524288);
|
|
|
|
|
tmp = malloc(524288);
|
|
|
|
|
|
|
|
|
|
r = mbedtls_base64_decode(tmp, 524288, &out, ca_cert_store_encoded, sizeof(ca_cert_store_encoded)-1);
|
|
|
|
|
if (r)
|
|
|
|
|
{
|
|
|
|
|
mbedtls_strerror(r, (char*)tmp, 524288);
|
|
|
|
|
printf("decoding failed: %s\n", tmp);
|
|
|
|
|
free(tmp);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
/* inflate ca certs, they are still compressed */
|
|
|
|
|
ca_certs = malloc(524288);
|
|
|
|
|
inf_len = 524288;
|
|
|
|
|
r = mbedtls_base64_decode(tmp, 524288, &out, ca_cert_store_encoded,
|
|
|
|
|
sizeof(ca_cert_store_encoded) - 1);
|
|
|
|
|
if(r)
|
|
|
|
|
{
|
|
|
|
|
mbedtls_strerror(r, (char *)tmp, 524288);
|
|
|
|
|
printf("decoding failed: %s\n", tmp);
|
|
|
|
|
free(tmp);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inf_status = uncompress(ca_certs, &inf_len, tmp, out);
|
|
|
|
|
if (inf_status != Z_OK)
|
|
|
|
|
{
|
|
|
|
|
printf("decompression failed: %s\n", mz_error(inf_status));
|
|
|
|
|
free(tmp);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
/* inflate ca certs, they are still compressed */
|
|
|
|
|
ca_certs = malloc(524288);
|
|
|
|
|
inf_len = 524288;
|
|
|
|
|
|
|
|
|
|
free(tmp);
|
|
|
|
|
inf_status = uncompress(ca_certs, &inf_len, tmp, out);
|
|
|
|
|
if(inf_status != Z_OK)
|
|
|
|
|
{
|
|
|
|
|
printf("decompression failed: %s\n", mz_error(inf_status));
|
|
|
|
|
free(tmp);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* On Windows NT 4.0 or later, use CryptoAPI to grab 64 bytes of random data */
|
|
|
|
|
hprovider = 0;
|
|
|
|
|
CryptAcquireContext(&hprovider, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT);
|
|
|
|
|
CryptGenRandom(hprovider, 64, (BYTE*)&seed);
|
|
|
|
|
CryptReleaseContext(hprovider, 0);
|
|
|
|
|
seed[63] = '\0'; /* null-terminate for safety */
|
|
|
|
|
free(tmp);
|
|
|
|
|
|
|
|
|
|
/* Seed the RNG with trash from /dev/urandom or CNG */
|
|
|
|
|
if(!get_noise())
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char*)seed, 64) != 0) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
r = mbedtls_x509_crt_parse(&cacert, ca_certs, inf_len+1);
|
|
|
|
|
if (r < 0) {
|
|
|
|
|
mbedtls_strerror(r, str, 512);
|
|
|
|
|
printf("parse ca cert store failed\n ! mbedtls_x509_crt_parse returned: %s\n\n", str);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
r = mbedtls_x509_crt_parse(&cacert, ca_certs, inf_len + 1);
|
|
|
|
|
if(r < 0)
|
|
|
|
|
{
|
|
|
|
|
mbedtls_strerror(r, str, 512);
|
|
|
|
|
printf(
|
|
|
|
|
"parse ca cert store failed\n ! mbedtls_x509_crt_parse returned: "
|
|
|
|
|
"%s\n\n",
|
|
|
|
|
str);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void free_parsed_url(url_parsed)
|
|
|
|
|
free_parsed_url(url_parsed)
|
|
|
|
|
url_parser_url_t *url_parsed;
|
|
|
|
|
{
|
|
|
|
|
if (url_parsed->protocol)
|
|
|
|
|
free(url_parsed->protocol);
|
|
|
|
|
if (url_parsed->host)
|
|
|
|
|
free(url_parsed->host);
|
|
|
|
|
if (url_parsed->path)
|
|
|
|
|
free(url_parsed->path);
|
|
|
|
|
if (url_parsed->query_string)
|
|
|
|
|
free(url_parsed->query_string);
|
|
|
|
|
if(url_parsed->protocol)
|
|
|
|
|
free(url_parsed->protocol);
|
|
|
|
|
if(url_parsed->host)
|
|
|
|
|
free(url_parsed->host);
|
|
|
|
|
if(url_parsed->path)
|
|
|
|
|
free(url_parsed->path);
|
|
|
|
|
if(url_parsed->query_string)
|
|
|
|
|
free(url_parsed->query_string);
|
|
|
|
|
|
|
|
|
|
free(url_parsed);
|
|
|
|
|
free(url_parsed);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
parse_url(url, verify_host, parsed_url)
|
|
|
|
@ -2288,316 +2389,341 @@ char *url;
|
|
|
|
|
bool verify_host;
|
|
|
|
|
url_parser_url_t *parsed_url;
|
|
|
|
|
{
|
|
|
|
|
char *local_url;
|
|
|
|
|
char *token;
|
|
|
|
|
char *token_host;
|
|
|
|
|
char *host_port;
|
|
|
|
|
char *host_ip;
|
|
|
|
|
char *local_url;
|
|
|
|
|
char *token;
|
|
|
|
|
char *token_host;
|
|
|
|
|
char *host_port;
|
|
|
|
|
char *host_ip;
|
|
|
|
|
|
|
|
|
|
char *token_ptr;
|
|
|
|
|
char *host_token_ptr;
|
|
|
|
|
|
|
|
|
|
char *token_ptr;
|
|
|
|
|
char *host_token_ptr;
|
|
|
|
|
char *path = NULL;
|
|
|
|
|
|
|
|
|
|
char *path = NULL;
|
|
|
|
|
/* Copy our string */
|
|
|
|
|
local_url = strdup(url);
|
|
|
|
|
|
|
|
|
|
/* Copy our string */
|
|
|
|
|
local_url = strdup(url);
|
|
|
|
|
token = strtok_r(local_url, ":", &token_ptr);
|
|
|
|
|
parsed_url->protocol = strdup(token);
|
|
|
|
|
|
|
|
|
|
token = strtok_r(local_url, ":", &token_ptr);
|
|
|
|
|
parsed_url->protocol = strdup(token);
|
|
|
|
|
/* Host:Port */
|
|
|
|
|
token = strtok_r(NULL, "/", &token_ptr);
|
|
|
|
|
if(token)
|
|
|
|
|
host_port = strdup(token);
|
|
|
|
|
else
|
|
|
|
|
host_port = (char *)calloc(1, sizeof(char));
|
|
|
|
|
|
|
|
|
|
/* Host:Port */
|
|
|
|
|
token = strtok_r(NULL, "/", &token_ptr);
|
|
|
|
|
if (token)
|
|
|
|
|
host_port = strdup(token);
|
|
|
|
|
else
|
|
|
|
|
host_port = (char *) calloc(1, sizeof(char));
|
|
|
|
|
token_host = strtok_r(host_port, ":", &host_token_ptr);
|
|
|
|
|
parsed_url->host_ip = NULL;
|
|
|
|
|
if(token_host)
|
|
|
|
|
{
|
|
|
|
|
parsed_url->host = strdup(token_host);
|
|
|
|
|
|
|
|
|
|
token_host = strtok_r(host_port, ":", &host_token_ptr);
|
|
|
|
|
parsed_url->host_ip = NULL;
|
|
|
|
|
if (token_host) {
|
|
|
|
|
parsed_url->host = strdup(token_host);
|
|
|
|
|
if(verify_host)
|
|
|
|
|
{
|
|
|
|
|
struct hostent *host;
|
|
|
|
|
host = gethostbyname(parsed_url->host);
|
|
|
|
|
if(host != NULL)
|
|
|
|
|
{
|
|
|
|
|
parsed_url->host_ip = inet_ntoa(*(struct in_addr *)host->h_addr);
|
|
|
|
|
parsed_url->host_exists = 1;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
parsed_url->host_exists = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
parsed_url->host_exists = -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
parsed_url->host_exists = -1;
|
|
|
|
|
parsed_url->host = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (verify_host) {
|
|
|
|
|
struct hostent *host;
|
|
|
|
|
host = gethostbyname(parsed_url->host);
|
|
|
|
|
if (host != NULL) {
|
|
|
|
|
parsed_url->host_ip = inet_ntoa(* (struct in_addr *) host->h_addr);
|
|
|
|
|
parsed_url->host_exists = 1;
|
|
|
|
|
} else {
|
|
|
|
|
parsed_url->host_exists = 0;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
parsed_url->host_exists = -1;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
parsed_url->host_exists = -1;
|
|
|
|
|
parsed_url->host = NULL;
|
|
|
|
|
}
|
|
|
|
|
/* Port */
|
|
|
|
|
token_host = strtok_r(NULL, ":", &host_token_ptr);
|
|
|
|
|
if(token_host)
|
|
|
|
|
parsed_url->port = atoi(token_host);
|
|
|
|
|
else
|
|
|
|
|
parsed_url->port = 0;
|
|
|
|
|
|
|
|
|
|
/* Port */
|
|
|
|
|
token_host = strtok_r(NULL, ":", &host_token_ptr);
|
|
|
|
|
if (token_host)
|
|
|
|
|
parsed_url->port = atoi(token_host);
|
|
|
|
|
else
|
|
|
|
|
parsed_url->port = 0;
|
|
|
|
|
token_host = strtok_r(NULL, ":", &host_token_ptr);
|
|
|
|
|
assert(token_host == NULL);
|
|
|
|
|
|
|
|
|
|
token_host = strtok_r(NULL, ":", &host_token_ptr);
|
|
|
|
|
assert(token_host == NULL);
|
|
|
|
|
token = strtok_r(NULL, "?", &token_ptr);
|
|
|
|
|
parsed_url->path = NULL;
|
|
|
|
|
if(token)
|
|
|
|
|
{
|
|
|
|
|
path = (char *)realloc(path, sizeof(char) * (strlen(token) + 2));
|
|
|
|
|
memset(path, 0, sizeof(char) * (strlen(token) + 2));
|
|
|
|
|
strcpy(path, "/");
|
|
|
|
|
strcat(path, token);
|
|
|
|
|
|
|
|
|
|
token = strtok_r(NULL, "?", &token_ptr);
|
|
|
|
|
parsed_url->path = NULL;
|
|
|
|
|
if (token) {
|
|
|
|
|
path = (char *) realloc(path, sizeof(char) * (strlen(token) + 2));
|
|
|
|
|
memset(path, 0, sizeof(char) * (strlen(token)+2));
|
|
|
|
|
strcpy(path, "/");
|
|
|
|
|
strcat(path, token);
|
|
|
|
|
parsed_url->path = strdup(path);
|
|
|
|
|
|
|
|
|
|
parsed_url->path = strdup(path);
|
|
|
|
|
free(path);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
parsed_url->path = (char *)malloc(sizeof(char) * 2);
|
|
|
|
|
strcpy(parsed_url->path, "/");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
free(path);
|
|
|
|
|
} else {
|
|
|
|
|
parsed_url->path = (char *) malloc(sizeof(char) * 2);
|
|
|
|
|
strcpy(parsed_url->path, "/");
|
|
|
|
|
}
|
|
|
|
|
token = strtok_r(NULL, "?", &token_ptr);
|
|
|
|
|
if(token)
|
|
|
|
|
{
|
|
|
|
|
parsed_url->query_string =
|
|
|
|
|
(char *)malloc(sizeof(char) * (strlen(token) + 1));
|
|
|
|
|
strncpy(parsed_url->query_string, token, strlen(token));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
parsed_url->query_string = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
token = strtok_r(NULL, "?", &token_ptr);
|
|
|
|
|
if (token) {
|
|
|
|
|
parsed_url->query_string = (char *) malloc(sizeof(char) * (strlen(token) + 1));
|
|
|
|
|
strncpy(parsed_url->query_string, token, strlen(token));
|
|
|
|
|
} else {
|
|
|
|
|
parsed_url->query_string = NULL;
|
|
|
|
|
}
|
|
|
|
|
token = strtok_r(NULL, "?", &token_ptr);
|
|
|
|
|
assert(token == NULL);
|
|
|
|
|
|
|
|
|
|
token = strtok_r(NULL, "?", &token_ptr);
|
|
|
|
|
assert(token == NULL);
|
|
|
|
|
free(local_url);
|
|
|
|
|
free(host_port);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
free(local_url);
|
|
|
|
|
free(host_port);
|
|
|
|
|
return 0;
|
|
|
|
|
terminate_unr()
|
|
|
|
|
{
|
|
|
|
|
mbedtls_ssl_close_notify(&ssl);
|
|
|
|
|
mbedtls_net_free(&server_fd);
|
|
|
|
|
mbedtls_x509_crt_free(&cacert);
|
|
|
|
|
mbedtls_ssl_free(&ssl);
|
|
|
|
|
mbedtls_ssl_config_free(&conf);
|
|
|
|
|
mbedtls_ctr_drbg_free(&ctr_drbg);
|
|
|
|
|
mbedtls_entropy_free(&entropy);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
connect_insecure(uri, ua, savePath)
|
|
|
|
|
connect_insecure(uri, ua, savePath)
|
|
|
|
|
url_parser_url_t *uri;
|
|
|
|
|
char *ua, *savePath;
|
|
|
|
|
{
|
|
|
|
|
int r, len;
|
|
|
|
|
FILE *bootstrapRC;
|
|
|
|
|
char rq[4096] = { 0 };
|
|
|
|
|
char buf[512] = { 0 };
|
|
|
|
|
char path[MAX_PATH] = { 0 };
|
|
|
|
|
char *resp;
|
|
|
|
|
int r, len;
|
|
|
|
|
FILE *bootstrapRC;
|
|
|
|
|
char rq[4096] = {0};
|
|
|
|
|
char buf[512] = {0};
|
|
|
|
|
char path[MAX_PATH] = {0};
|
|
|
|
|
char *resp;
|
|
|
|
|
|
|
|
|
|
printf("\nDownloading %s...", &uri->path[1]);
|
|
|
|
|
snprintf(rq, 512, "GET %s HTTP/1.0\r\nHost: %s\r\nUser-Agent: %s\r\n\r\n", uri->path, uri->host, ua);
|
|
|
|
|
while ((r = mbedtls_net_send(&ssl, (unsigned char*)rq, strlen(rq))) <= 0)
|
|
|
|
|
{
|
|
|
|
|
if (r != MBEDTLS_ERR_SSL_WANT_READ && r != MBEDTLS_ERR_SSL_WANT_WRITE)
|
|
|
|
|
{
|
|
|
|
|
printf("failed! error %d\n\n", r);
|
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
memset(rq, 0, 4096);
|
|
|
|
|
len = 0;
|
|
|
|
|
do {
|
|
|
|
|
r = mbedtls_net_recv(&ssl, (unsigned char*)buf, 512);
|
|
|
|
|
if (r <= 0)
|
|
|
|
|
break;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
strncat(rq, buf, r);
|
|
|
|
|
len += r;
|
|
|
|
|
}
|
|
|
|
|
} while (r);
|
|
|
|
|
printf("%d bytes downloaded to core.\n", len);
|
|
|
|
|
printf("\nDownloading %s...", &uri->path[1]);
|
|
|
|
|
snprintf(rq, 512, "GET %s HTTP/1.0\r\nHost: %s\r\nUser-Agent: %s\r\n\r\n",
|
|
|
|
|
uri->path, uri->host, ua);
|
|
|
|
|
while((r = mbedtls_net_send(&ssl, (unsigned char *)rq, strlen(rq))) <= 0)
|
|
|
|
|
{
|
|
|
|
|
if(r != MBEDTLS_ERR_SSL_WANT_READ && r != MBEDTLS_ERR_SSL_WANT_WRITE)
|
|
|
|
|
{
|
|
|
|
|
printf("failed! error %d\n\n", r);
|
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
memset(rq, 0, 4096);
|
|
|
|
|
len = 0;
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
r = mbedtls_net_recv(&ssl, (unsigned char *)buf, 512);
|
|
|
|
|
if(r <= 0)
|
|
|
|
|
break;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
strncat(rq, buf, r);
|
|
|
|
|
len += r;
|
|
|
|
|
}
|
|
|
|
|
} while(r);
|
|
|
|
|
printf("%d bytes downloaded to core.\n", len);
|
|
|
|
|
|
|
|
|
|
if (!strstr(rq, "200 OK"))
|
|
|
|
|
{
|
|
|
|
|
printf("An error occurred.\n");
|
|
|
|
|
printf("Server response:\n%s", rq);
|
|
|
|
|
/* TODO: extract HTTP error code and return that instead */
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
if(!strstr(rq, "200 OK"))
|
|
|
|
|
{
|
|
|
|
|
printf("An error occurred.\n");
|
|
|
|
|
printf("Server response:\n%s", rq);
|
|
|
|
|
/* TODO: extract HTTP error code and return that instead */
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
snprintf(path, MAX_PATH, savePath);
|
|
|
|
|
resp = strstr(rq, "Content-Length");
|
|
|
|
|
r = strcspn(resp, "0123456789");
|
|
|
|
|
snprintf(buf, 4, "%s", &resp[r]);
|
|
|
|
|
r = atoi(buf);
|
|
|
|
|
resp = strstr(rq, "\r\n\r\n");
|
|
|
|
|
snprintf(buf, r, "%s", &resp[4]);
|
|
|
|
|
printf("Writing %s...\n", path);
|
|
|
|
|
bootstrapRC = fopen(path, "wb");
|
|
|
|
|
fwrite(buf, 1, r, bootstrapRC);
|
|
|
|
|
fclose(bootstrapRC);
|
|
|
|
|
snprintf(path, MAX_PATH, savePath);
|
|
|
|
|
resp = strstr(rq, "Content-Length");
|
|
|
|
|
r = strcspn(resp, "0123456789");
|
|
|
|
|
snprintf(buf, 4, "%s", &resp[r]);
|
|
|
|
|
r = atoi(buf);
|
|
|
|
|
resp = strstr(rq, "\r\n\r\n");
|
|
|
|
|
snprintf(buf, r, "%s", &resp[4]);
|
|
|
|
|
printf("Writing %s...\n", path);
|
|
|
|
|
bootstrapRC = fopen(path, "wb");
|
|
|
|
|
fwrite(buf, 1, r, bootstrapRC);
|
|
|
|
|
fclose(bootstrapRC);
|
|
|
|
|
|
|
|
|
|
r = 0;
|
|
|
|
|
r = 0;
|
|
|
|
|
|
|
|
|
|
return r;
|
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
main(argc, argv)
|
|
|
|
|
char** argv; /* It never occurred to me that this was writable to begin with... */
|
|
|
|
|
main(argc, argv)
|
|
|
|
|
char **argv; /* It never occurred to me that this was writable to begin with... */
|
|
|
|
|
{
|
|
|
|
|
DWORD version, major, minor, build, flags;
|
|
|
|
|
int r, len;
|
|
|
|
|
FILE *bootstrapRC;
|
|
|
|
|
char path[MAX_PATH], buf[512], port[8];
|
|
|
|
|
char *ua, *rq, *resp, *uri, *savePath;
|
|
|
|
|
url_parser_url_t *parsed_uri;
|
|
|
|
|
DWORD version, major, minor, build, flags;
|
|
|
|
|
int r, len;
|
|
|
|
|
FILE *out_file;
|
|
|
|
|
char path[MAX_PATH], buf[512], port[8];
|
|
|
|
|
char *ua, *rq, *resp, *uri, *savePath;
|
|
|
|
|
url_parser_url_t *parsed_uri;
|
|
|
|
|
|
|
|
|
|
if (argc == 1)
|
|
|
|
|
{
|
|
|
|
|
printf("Usage: %s [uri] [savepath]\n", argv[0]);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
if(argc >= 3)
|
|
|
|
|
{
|
|
|
|
|
uri = argv[1];
|
|
|
|
|
savePath = argv[2];
|
|
|
|
|
parsed_uri = malloc(sizeof(url_parser_url_t));
|
|
|
|
|
memset(parsed_uri, 0, sizeof(url_parser_url_t));
|
|
|
|
|
r = parse_url(uri, false, parsed_uri);
|
|
|
|
|
if(r)
|
|
|
|
|
{
|
|
|
|
|
printf("Invalid URI pathspec\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (argc >= 3)
|
|
|
|
|
{
|
|
|
|
|
uri = argv[1];
|
|
|
|
|
savePath = argv[2];
|
|
|
|
|
parsed_uri = malloc(sizeof(url_parser_url_t));
|
|
|
|
|
memset(parsed_uri, 0, sizeof(url_parser_url_t));
|
|
|
|
|
r = parse_url(uri, false, parsed_uri);
|
|
|
|
|
if (r)
|
|
|
|
|
{
|
|
|
|
|
printf("Invalid URI pathspec\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if(!initTLS())
|
|
|
|
|
{
|
|
|
|
|
printf("Failed to initialise polarssl\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!initTLS())
|
|
|
|
|
{
|
|
|
|
|
printf("Failed to initialise polarssl\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* fill in user-agent string */
|
|
|
|
|
version = GetVersion();
|
|
|
|
|
major = (DWORD)(LOBYTE(LOWORD(version)));
|
|
|
|
|
minor = (DWORD)(HIBYTE(LOWORD(version)));
|
|
|
|
|
if (version < 0x80000000)
|
|
|
|
|
build = (DWORD)(HIWORD(version));
|
|
|
|
|
ua = malloc(512);
|
|
|
|
|
rq = malloc(4096);
|
|
|
|
|
snprintf(ua, 512, "%s%d.%d", userAgent, major, minor);
|
|
|
|
|
/* fill in user-agent string */
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
|
version = GetVersion();
|
|
|
|
|
major = (DWORD)(LOBYTE(LOWORD(version)));
|
|
|
|
|
minor = (DWORD)(HIBYTE(LOWORD(version)));
|
|
|
|
|
if(version < 0x80000000)
|
|
|
|
|
build = (DWORD)(HIWORD(version));
|
|
|
|
|
#endif
|
|
|
|
|
ua = malloc(512);
|
|
|
|
|
rq = malloc(4096);
|
|
|
|
|
snprintf(ua, 512, "%s%d.%d", userAgent, major, minor);
|
|
|
|
|
|
|
|
|
|
/* get host name, set port if blank */
|
|
|
|
|
if (!strcmp("https", parsed_uri->protocol) && !parsed_uri->port)
|
|
|
|
|
parsed_uri->port = 443;
|
|
|
|
|
if (!strcmp("http", parsed_uri->protocol) && !parsed_uri->port)
|
|
|
|
|
parsed_uri->port = 80;
|
|
|
|
|
/* get host name, set port if blank */
|
|
|
|
|
if(!strcmp("https", parsed_uri->protocol) && !parsed_uri->port)
|
|
|
|
|
parsed_uri->port = 443;
|
|
|
|
|
if(!strcmp("http", parsed_uri->protocol) && !parsed_uri->port)
|
|
|
|
|
parsed_uri->port = 80;
|
|
|
|
|
|
|
|
|
|
printf("connecting to %s on port %d...",parsed_uri->host, parsed_uri->port);
|
|
|
|
|
sprintf(port, "%d", parsed_uri->port);
|
|
|
|
|
r = mbedtls_net_connect(&server_fd, parsed_uri->host, port, MBEDTLS_NET_PROTO_TCP);
|
|
|
|
|
if (r)
|
|
|
|
|
{
|
|
|
|
|
printf("error - failed to connect to server: %d\n", r);
|
|
|
|
|
goto exit;
|
|
|
|
|
}
|
|
|
|
|
printf("connecting to %s on port %d...", parsed_uri->host, parsed_uri->port);
|
|
|
|
|
sprintf(port, "%d", parsed_uri->port);
|
|
|
|
|
r = mbedtls_net_connect(&server_fd, parsed_uri->host, port,
|
|
|
|
|
MBEDTLS_NET_PROTO_TCP);
|
|
|
|
|
if(r)
|
|
|
|
|
{
|
|
|
|
|
printf("error - failed to connect to server: %d\n", r);
|
|
|
|
|
goto exit;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ok this is where the secure vs insecure stuff splits off */
|
|
|
|
|
if (strcmp(parsed_uri->protocol, "https"))
|
|
|
|
|
{
|
|
|
|
|
r = connect_insecure(parsed_uri, ua, savePath);
|
|
|
|
|
goto exit;
|
|
|
|
|
}
|
|
|
|
|
/* ok this is where the secure vs insecure stuff splits off */
|
|
|
|
|
if(strcmp(parsed_uri->protocol, "https"))
|
|
|
|
|
{
|
|
|
|
|
r = connect_insecure(parsed_uri, ua, savePath);
|
|
|
|
|
goto exit;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* HTTPS sequence */
|
|
|
|
|
r = mbedtls_ssl_config_defaults(&conf, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT);
|
|
|
|
|
if (r)
|
|
|
|
|
{
|
|
|
|
|
printf("error - failed to set TLS options: %d\n", r);
|
|
|
|
|
goto exit;
|
|
|
|
|
}
|
|
|
|
|
mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_REQUIRED);
|
|
|
|
|
mbedtls_ssl_conf_ca_chain(&conf, &cacert, NULL);
|
|
|
|
|
mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg);
|
|
|
|
|
r = mbedtls_ssl_setup(&ssl, &conf);
|
|
|
|
|
if (r)
|
|
|
|
|
{
|
|
|
|
|
printf("error - failed to setup TLS session: %d\n", r);
|
|
|
|
|
goto exit;
|
|
|
|
|
}
|
|
|
|
|
r = mbedtls_ssl_set_hostname(&ssl, parsed_uri->host);
|
|
|
|
|
if (r)
|
|
|
|
|
{
|
|
|
|
|
printf("error - failed to perform SNI: %d\n", r);
|
|
|
|
|
goto exit;
|
|
|
|
|
}
|
|
|
|
|
mbedtls_ssl_set_bio(&ssl, &server_fd, mbedtls_net_send, mbedtls_net_recv, NULL);
|
|
|
|
|
while ((r = mbedtls_ssl_handshake(&ssl)) != 0)
|
|
|
|
|
{
|
|
|
|
|
if (r != MBEDTLS_ERR_SSL_WANT_READ && r != MBEDTLS_ERR_SSL_WANT_WRITE)
|
|
|
|
|
{
|
|
|
|
|
printf(" failed\n ! mbedtls_ssl_handshake returned -0x%x\n\n", -r);
|
|
|
|
|
goto exit;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if ((flags = mbedtls_ssl_get_verify_result(&ssl)) != 0)
|
|
|
|
|
{
|
|
|
|
|
char vrfy_buf[512];
|
|
|
|
|
printf(" failed\n");
|
|
|
|
|
mbedtls_x509_crt_verify_info(vrfy_buf, sizeof(vrfy_buf), " ! ", flags);
|
|
|
|
|
printf("%s\n", vrfy_buf);
|
|
|
|
|
goto exit;
|
|
|
|
|
}
|
|
|
|
|
printf("\nDownloading %s...", &parsed_uri->path[1]);
|
|
|
|
|
snprintf(rq, 512, "GET %s HTTP/1.0\r\nHost: %s\r\nUser-Agent: %s\r\n\r\n", parsed_uri->path, parsed_uri->host, ua);
|
|
|
|
|
while ((r = mbedtls_ssl_write(&ssl, (unsigned char*)rq, strlen(rq))) <= 0)
|
|
|
|
|
{
|
|
|
|
|
if (r != MBEDTLS_ERR_SSL_WANT_READ && r != MBEDTLS_ERR_SSL_WANT_WRITE)
|
|
|
|
|
{
|
|
|
|
|
printf("failed! error %d\n\n", r);
|
|
|
|
|
goto exit;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
memset(rq, 0, 4096);
|
|
|
|
|
len = 0;
|
|
|
|
|
do {
|
|
|
|
|
r = mbedtls_ssl_read(&ssl, (unsigned char*)buf, 512);
|
|
|
|
|
if (r <= 0)
|
|
|
|
|
break;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
strncat(rq, buf, r);
|
|
|
|
|
len += r;
|
|
|
|
|
}
|
|
|
|
|
} while (r);
|
|
|
|
|
printf("%d bytes downloaded to core.\n", len);
|
|
|
|
|
mbedtls_ssl_close_notify(&ssl);
|
|
|
|
|
if (!strstr(rq, "200 OK"))
|
|
|
|
|
{
|
|
|
|
|
printf("An error occurred.\n");
|
|
|
|
|
printf("Server response:\n%s", rq);
|
|
|
|
|
goto exit;
|
|
|
|
|
}
|
|
|
|
|
snprintf(path, MAX_PATH, savePath);
|
|
|
|
|
resp = strstr(rq, "Content-Length");
|
|
|
|
|
r = strcspn(resp, "0123456789");
|
|
|
|
|
snprintf(buf, 4, "%s", &resp[r]);
|
|
|
|
|
r = atoi(buf);
|
|
|
|
|
resp = strstr(rq, "\r\n\r\n");
|
|
|
|
|
snprintf(buf, r, "%s", &resp[4]);
|
|
|
|
|
printf("Writing %s...\n", path);
|
|
|
|
|
bootstrapRC = fopen(path, "wb");
|
|
|
|
|
fwrite(buf, 1, r, bootstrapRC);
|
|
|
|
|
fclose(bootstrapRC);
|
|
|
|
|
/* HTTPS sequence */
|
|
|
|
|
r = mbedtls_ssl_config_defaults(&conf, MBEDTLS_SSL_IS_CLIENT,
|
|
|
|
|
MBEDTLS_SSL_TRANSPORT_STREAM,
|
|
|
|
|
MBEDTLS_SSL_PRESET_DEFAULT);
|
|
|
|
|
if(r)
|
|
|
|
|
{
|
|
|
|
|
printf("error - failed to set TLS options: %d\n", r);
|
|
|
|
|
goto exit;
|
|
|
|
|
}
|
|
|
|
|
mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_REQUIRED);
|
|
|
|
|
mbedtls_ssl_conf_ca_chain(&conf, &cacert, NULL);
|
|
|
|
|
mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg);
|
|
|
|
|
r = mbedtls_ssl_setup(&ssl, &conf);
|
|
|
|
|
if(r)
|
|
|
|
|
{
|
|
|
|
|
printf("error - failed to setup TLS session: %d\n", r);
|
|
|
|
|
goto exit;
|
|
|
|
|
}
|
|
|
|
|
r = mbedtls_ssl_set_hostname(&ssl, parsed_uri->host);
|
|
|
|
|
if(r)
|
|
|
|
|
{
|
|
|
|
|
printf("error - failed to perform SNI: %d\n", r);
|
|
|
|
|
goto exit;
|
|
|
|
|
}
|
|
|
|
|
mbedtls_ssl_set_bio(&ssl, &server_fd, mbedtls_net_send, mbedtls_net_recv,
|
|
|
|
|
NULL);
|
|
|
|
|
while((r = mbedtls_ssl_handshake(&ssl)) != 0)
|
|
|
|
|
{
|
|
|
|
|
if(r != MBEDTLS_ERR_SSL_WANT_READ && r != MBEDTLS_ERR_SSL_WANT_WRITE)
|
|
|
|
|
{
|
|
|
|
|
printf(" failed\n ! mbedtls_ssl_handshake returned -0x%x\n\n", -r);
|
|
|
|
|
goto exit;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if((flags = mbedtls_ssl_get_verify_result(&ssl)) != 0)
|
|
|
|
|
{
|
|
|
|
|
char vrfy_buf[512];
|
|
|
|
|
printf(" failed\n");
|
|
|
|
|
mbedtls_x509_crt_verify_info(vrfy_buf, sizeof(vrfy_buf), " ! ", flags);
|
|
|
|
|
printf("%s\n", vrfy_buf);
|
|
|
|
|
goto exit;
|
|
|
|
|
}
|
|
|
|
|
printf("\nDownloading %s...", &parsed_uri->path[1]);
|
|
|
|
|
snprintf(rq, 512, "GET %s HTTP/1.0\r\nHost: %s\r\nUser-Agent: %s\r\n\r\n",
|
|
|
|
|
parsed_uri->path, parsed_uri->host, ua);
|
|
|
|
|
while((r = mbedtls_ssl_write(&ssl, (unsigned char *)rq, strlen(rq))) <= 0)
|
|
|
|
|
{
|
|
|
|
|
if(r != MBEDTLS_ERR_SSL_WANT_READ && r != MBEDTLS_ERR_SSL_WANT_WRITE)
|
|
|
|
|
{
|
|
|
|
|
printf("failed! error %d\n\n", r);
|
|
|
|
|
goto exit;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
memset(rq, 0, 4096);
|
|
|
|
|
len = 0;
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
r = mbedtls_ssl_read(&ssl, (unsigned char *)buf, 512);
|
|
|
|
|
if(r <= 0)
|
|
|
|
|
break;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
strncat(rq, buf, r);
|
|
|
|
|
len += r;
|
|
|
|
|
}
|
|
|
|
|
} while(r);
|
|
|
|
|
printf("%d bytes downloaded to core.\n", len);
|
|
|
|
|
mbedtls_ssl_close_notify(&ssl);
|
|
|
|
|
if(!strstr(rq, "200 OK"))
|
|
|
|
|
{
|
|
|
|
|
printf("An error occurred.\n");
|
|
|
|
|
printf("Server response:\n%s", rq);
|
|
|
|
|
goto exit;
|
|
|
|
|
}
|
|
|
|
|
snprintf(path, MAX_PATH, savePath);
|
|
|
|
|
resp = strstr(rq, "Content-Length");
|
|
|
|
|
r = strcspn(resp, "0123456789");
|
|
|
|
|
snprintf(buf, 4, "%s", &resp[r]);
|
|
|
|
|
r = atoi(buf);
|
|
|
|
|
resp = strstr(rq, "\r\n\r\n");
|
|
|
|
|
snprintf(buf, r, "%s", &resp[4]);
|
|
|
|
|
printf("Writing %s...\n", path);
|
|
|
|
|
bootstrapRC = fopen(path, "wb");
|
|
|
|
|
fwrite(buf, 1, r, bootstrapRC);
|
|
|
|
|
fclose(bootstrapRC);
|
|
|
|
|
|
|
|
|
|
r = 0;
|
|
|
|
|
r = 0;
|
|
|
|
|
|
|
|
|
|
exit:
|
|
|
|
|
mbedtls_ssl_close_notify(&ssl);
|
|
|
|
|
mbedtls_net_free(&server_fd);
|
|
|
|
|
mbedtls_x509_crt_free(&cacert);
|
|
|
|
|
mbedtls_ssl_free(&ssl);
|
|
|
|
|
mbedtls_ssl_config_free(&conf);
|
|
|
|
|
mbedtls_ctr_drbg_free(&ctr_drbg);
|
|
|
|
|
mbedtls_entropy_free(&entropy);
|
|
|
|
|
free(ua);
|
|
|
|
|
free(rq);
|
|
|
|
|
free(ca_certs);
|
|
|
|
|
free_parsed_url(parsed_uri);
|
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
free(ua);
|
|
|
|
|
free(rq);
|
|
|
|
|
free(ca_certs);
|
|
|
|
|
free_parsed_url(parsed_uri);
|
|
|
|
|
terminate_unr();
|
|
|
|
|
return r;
|
|
|
|
|
}
|