Don't hardcode the signature length

This commit is contained in:
Cameron Gutman 2023-11-29 23:48:09 -06:00
parent 2aba7a10e7
commit 000d9da4a0

View File

@ -48,7 +48,7 @@
static char unique_id[UNIQUEID_CHARS+1];
static X509 *cert;
static char cert_hex[4096];
static char cert_hex[8192];
static EVP_PKEY *privateKey;
const char* gs_error;
@ -56,8 +56,6 @@ const char* gs_error;
#define LEN_AS_HEX_STR(x) ((x) * 2 + 1)
#define SIZEOF_AS_HEX_STR(x) LEN_AS_HEX_STR(sizeof(x))
#define SIGNATURE_LEN 256
#define UUID_STRLEN 37
static int mkdirtree(const char* directory) {
@ -310,6 +308,12 @@ static void bytes_to_hex(unsigned char *in, char *out, size_t len) {
out[len * 2] = 0;
}
static void hex_to_bytes(const char *in, unsigned char* out, size_t len) {
for (int count = 0; count < len; count += 2) {
sscanf(&in[count], "%2hhx", &out[count / 2]);
}
}
static int sign_it(const char *msg, size_t mlen, unsigned char **sig, size_t *slen, EVP_PKEY *pkey) {
int result = GS_FAILED;
@ -422,13 +426,20 @@ int gs_unpair(PSERVER_DATA server) {
int gs_pair(PSERVER_DATA server, char* pin) {
int ret = GS_OK;
char* result = NULL;
char url[5120];
size_t url_max_len = 16384;
char* url = malloc(url_max_len);
uuid_t uuid;
char uuid_str[UUID_STRLEN];
char* plaincert = NULL;
char* challenge_response = NULL;
char* pairing_secret = NULL;
char* client_pairing_secret = NULL;
char* client_pairing_secret_hex = NULL;
if (server->paired) {
gs_error = "Already paired";
return GS_WRONG_STATE;
ret = GS_WRONG_STATE;
goto cleanup;
}
unsigned char salt_data[16];
@ -438,7 +449,7 @@ int gs_pair(PSERVER_DATA server, char* pin) {
uuid_generate_random(uuid);
uuid_unparse(uuid, uuid_str);
snprintf(url, sizeof(url), "http://%s:%u/pair?uniqueid=%s&uuid=%s&devicename=roth&updateState=1&phrase=getservercert&salt=%s&clientcert=%s", server->serverInfo.address, server->httpPort, unique_id, uuid_str, salt_hex, cert_hex);
snprintf(url, url_max_len, "http://%s:%u/pair?uniqueid=%s&uuid=%s&devicename=roth&updateState=1&phrase=getservercert&salt=%s&clientcert=%s", server->serverInfo.address, server->httpPort, unique_id, uuid_str, salt_hex, cert_hex);
PHTTP_DATA data = http_create_data();
if (data == NULL)
return GS_OUT_OF_MEMORY;
@ -461,18 +472,11 @@ int gs_pair(PSERVER_DATA server, char* pin) {
if ((ret = xml_search(data->memory, data->size, "plaincert", &result)) != GS_OK)
goto cleanup;
char plaincert[8192];
if (strlen(result)/2 > sizeof(plaincert) - 1) {
gs_error = "Server certificate too big";
ret = GS_FAILED;
goto cleanup;
}
for (int count = 0; count < strlen(result); count += 2) {
sscanf(&result[count], "%2hhx", &plaincert[count / 2]);
}
plaincert[strlen(result)/2] = '\0';
size_t plaincertlen = strlen(result)/2;
plaincert = malloc(plaincertlen + 1);
hex_to_bytes(result, plaincert, plaincertlen*2);
plaincert[plaincertlen] = 0;
unsigned char salt_pin[sizeof(salt_data) + 4];
unsigned char aes_key[32]; // Must fit SHA256
@ -494,7 +498,7 @@ int gs_pair(PSERVER_DATA server, char* pin) {
uuid_generate_random(uuid);
uuid_unparse(uuid, uuid_str);
snprintf(url, sizeof(url), "http://%s:%u/pair?uniqueid=%s&uuid=%s&devicename=roth&updateState=1&clientchallenge=%s", server->serverInfo.address, server->httpPort, unique_id, uuid_str, challenge_hex);
snprintf(url, url_max_len, "http://%s:%u/pair?uniqueid=%s&uuid=%s&devicename=roth&updateState=1&clientchallenge=%s", server->serverInfo.address, server->httpPort, unique_id, uuid_str, challenge_hex);
if ((ret = http_request(url, data)) != GS_OK)
goto cleanup;
@ -527,10 +531,7 @@ int gs_pair(PSERVER_DATA server, char* pin) {
goto cleanup;
}
for (int count = 0; count < strlen(result); count += 2) {
sscanf(&result[count], "%2hhx", &challenge_response_data_enc[count / 2]);
}
hex_to_bytes(result, challenge_response_data_enc, strlen(result));
decrypt(challenge_response_data_enc, sizeof(challenge_response_data_enc), aes_key, challenge_response_data);
char client_secret_data[16];
@ -539,7 +540,7 @@ int gs_pair(PSERVER_DATA server, char* pin) {
const ASN1_BIT_STRING *asnSignature;
X509_get0_signature(&asnSignature, NULL, cert);
char challenge_response[16 + SIGNATURE_LEN + sizeof(client_secret_data)];
challenge_response = malloc(16 + asnSignature->length + sizeof(client_secret_data));
char challenge_response_hash[32];
char challenge_response_hash_enc[sizeof(challenge_response_hash)];
char challenge_response_hex[SIZEOF_AS_HEX_STR(challenge_response_hash_enc)];
@ -556,7 +557,7 @@ int gs_pair(PSERVER_DATA server, char* pin) {
uuid_generate_random(uuid);
uuid_unparse(uuid, uuid_str);
snprintf(url, sizeof(url), "http://%s:%u/pair?uniqueid=%s&uuid=%s&devicename=roth&updateState=1&serverchallengeresp=%s", server->serverInfo.address, server->httpPort, unique_id, uuid_str, challenge_response_hex);
snprintf(url, url_max_len, "http://%s:%u/pair?uniqueid=%s&uuid=%s&devicename=roth&updateState=1&serverchallengeresp=%s", server->serverInfo.address, server->httpPort, unique_id, uuid_str, challenge_response_hex);
if ((ret = http_request(url, data)) != GS_OK)
goto cleanup;
@ -580,19 +581,15 @@ int gs_pair(PSERVER_DATA server, char* pin) {
goto cleanup;
}
char pairing_secret[16 + SIGNATURE_LEN];
if (strlen(result) / 2 > sizeof(pairing_secret)) {
gs_error = "Pairing secret too big";
ret = GS_FAILED;
size_t pairing_secret_len = strlen(result) / 2;
if (pairing_secret_len <= 16) {
ret = GS_INVALID;
goto cleanup;
}
for (int count = 0; count < strlen(result); count += 2) {
sscanf(&result[count], "%2hhx", &pairing_secret[count / 2]);
}
if (!verifySignature(pairing_secret, 16, pairing_secret+16, SIGNATURE_LEN, plaincert)) {
pairing_secret = malloc(pairing_secret_len);
hex_to_bytes(result, pairing_secret, pairing_secret_len*2);
if (!verifySignature(pairing_secret, 16, pairing_secret+16, pairing_secret_len-16, plaincert)) {
gs_error = "MITM attack detected";
ret = GS_FAILED;
goto cleanup;
@ -606,15 +603,15 @@ int gs_pair(PSERVER_DATA server, char* pin) {
goto cleanup;
}
char client_pairing_secret[sizeof(client_secret_data) + SIGNATURE_LEN];
char client_pairing_secret_hex[SIZEOF_AS_HEX_STR(client_pairing_secret)];
client_pairing_secret = malloc(sizeof(client_secret_data) + s_len);
client_pairing_secret_hex = malloc(LEN_AS_HEX_STR(sizeof(client_secret_data) + s_len));
memcpy(client_pairing_secret, client_secret_data, sizeof(client_secret_data));
memcpy(client_pairing_secret + sizeof(client_secret_data), signature, SIGNATURE_LEN);
bytes_to_hex(client_pairing_secret, client_pairing_secret_hex, sizeof(client_secret_data) + SIGNATURE_LEN);
memcpy(client_pairing_secret + sizeof(client_secret_data), signature, s_len);
bytes_to_hex(client_pairing_secret, client_pairing_secret_hex, sizeof(client_secret_data) + s_len);
uuid_generate_random(uuid);
uuid_unparse(uuid, uuid_str);
snprintf(url, sizeof(url), "http://%s:%u/pair?uniqueid=%s&uuid=%s&devicename=roth&updateState=1&clientpairingsecret=%s", server->serverInfo.address, server->httpPort, unique_id, uuid_str, client_pairing_secret_hex);
snprintf(url, url_max_len, "http://%s:%u/pair?uniqueid=%s&uuid=%s&devicename=roth&updateState=1&clientpairingsecret=%s", server->serverInfo.address, server->httpPort, unique_id, uuid_str, client_pairing_secret_hex);
if ((ret = http_request(url, data)) != GS_OK)
goto cleanup;
@ -633,7 +630,7 @@ int gs_pair(PSERVER_DATA server, char* pin) {
uuid_generate_random(uuid);
uuid_unparse(uuid, uuid_str);
snprintf(url, sizeof(url), "https://%s:%u/pair?uniqueid=%s&uuid=%s&devicename=roth&updateState=1&phrase=pairchallenge", server->serverInfo.address, server->httpsPort, unique_id, uuid_str);
snprintf(url, url_max_len, "https://%s:%u/pair?uniqueid=%s&uuid=%s&devicename=roth&updateState=1&phrase=pairchallenge", server->serverInfo.address, server->httpsPort, unique_id, uuid_str);
if ((ret = http_request(url, data)) != GS_OK)
goto cleanup;
@ -656,8 +653,13 @@ int gs_pair(PSERVER_DATA server, char* pin) {
if (ret != GS_OK)
gs_unpair(server);
if (result != NULL)
free(result);
free(url);
free(plaincert);
free(challenge_response);
free(pairing_secret);
free(client_pairing_secret);
free(client_pairing_secret_hex);
free(result);
http_free_data(data);