From dd30aa72a899848538c7f2b5f0e8aa4bccb07c1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89rico=20Rolim?= Date: Sat, 12 Sep 2020 22:55:46 -0300 Subject: [PATCH] Split encrypt.c and fix use-after-free. UAF from genalloc and stralloc frees. Also remove randomization of IV, not used in bsd.ac. --- encrypt.c | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ makefile | 2 +- purr.c | 83 ++--------------------------------------------- purr.h | 5 +++ 4 files changed, 105 insertions(+), 82 deletions(-) create mode 100644 encrypt.c diff --git a/encrypt.c b/encrypt.c new file mode 100644 index 0000000..3e5e7d9 --- /dev/null +++ b/encrypt.c @@ -0,0 +1,97 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "purr.h" + +int encrypt_FILE(FILE **filep, uint8_t **keyp, uint8_t **ivp, char **tempp) +{ + FILE *input = *filep; + uint8_t *key = *keyp; + uint8_t *iv = *ivp; + char *temp = *tempp; + + if (input == stdin) { + fputs("currently can't encrypt stdin!\n", stderr); + return -1; + } + struct stat s; + int errs = fstat(fileno(input), &s); + if (errs != 0) { + perror("couldn't stat output!"); + return -1; + } + off_t file_size = s.st_size; + ssize_t blocks = file_size / br_aes_big_BLOCK_SIZE; + if (blocks * br_aes_big_BLOCK_SIZE < file_size) blocks++; + file_size = blocks * br_aes_big_BLOCK_SIZE; + + key = calloc(KEY_LEN, 1); + iv = calloc(IV_LEN, 1); + if (key == NULL || iv == NULL) { + perror("allocation failure"); + return -1; + } + + ssize_t err = getrandom(key, KEY_LEN, 0); + if (err != KEY_LEN) { + fputs("getrandom() error!\n", stderr); + return -1; + } + + #ifndef NO_RANDOMIZE_IV + err = getrandom(iv, IV_LEN, 0); + if (err != IV_LEN) { + fputs("getrandom() error!\n", stderr); + return -1; + } + #endif + + temp = strdup("/tmp/purrito.XXXXXX"); + int tfd = mkstemp(temp); + if (tfd < 0) { + perror("couldn't create temp file"); + return -1; + } + int errfa = posix_fallocate(tfd, 0, file_size); + if (errfa) { + perror("error while fallocating"); + return -1; + } + uint8_t *temp_map = + mmap(NULL, file_size, PROT_WRITE, MAP_SHARED, tfd, 0); + if (temp_map == NULL) { + perror("mmap failure"); + return -1; + } + close(tfd); + + for (ssize_t i = 0; i < blocks; i++) { + // zero padding for the last round + uint8_t tmp[br_aes_big_BLOCK_SIZE] = { 0 }; + fread(tmp, 1, br_aes_big_BLOCK_SIZE, input); + memcpy(temp_map + i * br_aes_big_BLOCK_SIZE, tmp, br_aes_big_BLOCK_SIZE); + } + + br_aes_big_cbcenc_keys br = { 0 }; + br_aes_big_cbcenc_init(&br, key, KEY_LEN); + br_aes_big_cbcenc_run(&br, iv, temp_map, file_size); + + fclose(input); + munmap(temp_map, file_size); + + input = fopen(temp, "r"); + if (input == NULL) { + perror("couldn't read temp file"); + return -1; + } + fstat(fileno(input), &s); + fprintf(stderr, "output file size: %lu\n", s.st_size); + + return 0; +} diff --git a/makefile b/makefile index c7ab49f..b323f3e 100644 --- a/makefile +++ b/makefile @@ -2,7 +2,7 @@ CFLAGS = -O2 -g -pipe -Wall -Wextra LDLIBS = -lbearssl -lsbearssl -lskarnet FINAL = purr -OBJS = purr.o socket.o urls.o files.o comm.o formats.o +OBJS = purr.o socket.o urls.o files.o comm.o formats.o encrypt.o all: $(FINAL) diff --git a/purr.c b/purr.c index 4dc4bd9..6ff31f0 100644 --- a/purr.c +++ b/purr.c @@ -1,15 +1,9 @@ #include -#include #include #include #include #include #include -#include -#include - -#include -#include #include #include @@ -218,8 +212,6 @@ int main (int argc, char **argv) { size_t i = num_ta; while(i--) sbearssl_ta_to(genalloc_s(sbearssl_ta, &ta_list) + i, btas + i, ta_content.s); - genalloc_free(sbearssl_ta, &ta_list); - stralloc_free(&ta_content); } br_ssl_client_init_full(&sc, &xc, btas, num_ta); @@ -231,79 +223,8 @@ int main (int argc, char **argv) uint8_t *iv = NULL; char *temp = NULL; if (send && encrypt) { - if (input == stdin) { - fputs("currently can't encrypt stdin!\n", stderr); - goto early_out; - } - struct stat s; - int errs = fstat(fileno(input), &s); - if (errs != 0) { - perror("couldn't stat output!"); - goto early_out; - } - off_t file_size = s.st_size; - ssize_t blocks = file_size / br_aes_big_BLOCK_SIZE; - if (blocks * br_aes_big_BLOCK_SIZE < file_size) blocks++; - file_size = blocks * br_aes_big_BLOCK_SIZE; - - key = calloc(KEY_LEN, 1); - iv = calloc(IV_LEN, 1); - if (key == NULL || iv == NULL) { - perror("allocation failure"); - goto early_out; - } - - ssize_t err = getrandom(key, KEY_LEN, 0); - if (err != KEY_LEN) { - fputs("getrandom() error!\n", stderr); - goto early_out; - } - err = getrandom(iv, IV_LEN, 0); - if (err != IV_LEN) { - fputs("getrandom() error!\n", stderr); - goto early_out; - } - - temp = strdup("/tmp/purrito.XXXXXX"); - int tfd = mkstemp(temp); - if (tfd < 0) { - perror("couldn't create temp file"); - goto early_out; - } - int errfa = posix_fallocate(tfd, 0, file_size); - if (errfa) { - perror("error while fallocating"); - goto early_out; - } - uint8_t *temp_map = - mmap(NULL, file_size, PROT_WRITE, MAP_SHARED, tfd, 0); - if (temp_map == NULL) { - perror("mmap failure"); - goto early_out; - } - close(tfd); - - for (ssize_t i = 0; i < blocks; i++) { - // zero padding for the last round - uint8_t tmp[br_aes_big_BLOCK_SIZE] = { 0 }; - fread(tmp, 1, br_aes_big_BLOCK_SIZE, output); - memcpy(temp_map + i * br_aes_big_BLOCK_SIZE, tmp, br_aes_big_BLOCK_SIZE); - } - - br_aes_big_cbcenc_keys br = { 0 }; - br_aes_big_cbcenc_init(&br, key, KEY_LEN); - br_aes_big_cbcenc_run(&br, iv, temp_map, file_size); - - fclose(output); - munmap(temp_map, file_size); - - output = fopen(temp, "r"); - if (output == NULL) { - perror("couldn't read temp file"); - goto early_out; - } - fstat(fileno(output), &s); - fprintf(stderr, "output file size: %lu\n", s.st_size); + // requires error checking + encrypt_FILE(&input, &key, &iv, &temp); } int socket = host_connect(link, port, debug); diff --git a/purr.h b/purr.h index 8b33324..c9f9a9a 100644 --- a/purr.h +++ b/purr.h @@ -15,6 +15,8 @@ #define KEY_LEN 32 #define IV_LEN br_aes_big_BLOCK_SIZE +#define NO_RANDOMIZE_IV + struct strip_header_info { FILE *output; char *header; @@ -59,4 +61,7 @@ int send_and_receive(struct connection_information *); /* formats.c */ void print_hex(uint8_t *, int); +/* encrypt.c */ +int encrypt_FILE(FILE **, uint8_t **, uint8_t **, char **); + #endif // __PURR_H_