Fix read_certs to receive FILE instead of a path.

This change lead to completely overhauling the bearssl_read_certs()
function, which now deals directly with FILES, instead of depending on
mmap_file. There is some slight added complexity for dealing with the
file reads.

The idea for this came from the idea of implementing path resolution
using openat() instead of path concatenation, so there was a need to
pass either fds or file streams to functions instead of specific paths.
This commit is contained in:
Érico Rolim 2020-10-16 01:05:24 -03:00
parent 8100addb24
commit 367fbc823f
3 changed files with 86 additions and 48 deletions

79
gemi.c
View File

@ -1,10 +1,13 @@
#define _POSIX_C_SOURCE 200809L /* getopt, scandir */
#define _POSIX_C_SOURCE 200809L /* getopt, scandir, openat */
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <dirent.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "purr.h"
#include "mmap_file.h"
@ -137,35 +140,57 @@ int main(int argc, char **argv)
}
const char *home = getenv("HOME");
const char *config = ".config/gemi";
const int path_max = PATH_MAX;
char config_tmp[PATH_MAX];
if (home) {
if (snprintf(config_tmp, path_max, "%s/%s", home, config) >= path_max) {
fputs("path is too long!\n", stderr);
goto early_out;
char config[PATH_MAX];
if (snprintf(config, PATH_MAX, "%s/%s", home, ".config/gemi") >= PATH_MAX) {
fputs("HOME is too long!\n", stderr);
goto stop_search;
}
config = config_tmp;
int config_fd = open(config, O_DIRECTORY | O_PATH | O_CLOEXEC);
if (config_fd < 0) {
perror("open()");
goto stop_search;
}
struct dirent **files = NULL;
// XXX: ideally, should use scandirat(2), but that's currently glibc only
int filenum = scandir(config, &files, dirfilter, alphasort);
if (filenum < 0) {
if (debug) {
perror("scandir()");
fprintf(stderr, "error reading configuration directory '%s'\n", config);
}
goto stop_search;
}
for (int i = 0; i < filenum; i++) {
int file = openat(config_fd, files[i]->d_name, O_RDONLY | O_CLOEXEC);
if (file < 0) {
perror("openat()");
goto loop_end;
}
struct stat st;
fstat(file, &st);
if ((st.st_mode & S_IFMT) == S_IFREG) {
FILE *file_stream = fdopen(file, "re");
if (file_stream == NULL) {
close(file);
goto loop_end;
}
if (bearssl_read_certs(&btas, file_stream) == 0) {
if (debug) fprintf(stderr, "error reading cert file: '%s'\n", files[i]->d_name);
}
} else {
close(file);
}
loop_end:
free(files[i]);
}
free(files);
}
struct dirent **files = NULL;
int filenum = scandir(config, &files, dirfilter, alphasort);
if (filenum < 0) {
if (debug) {
perror("scandir()");
fprintf(stderr, "error reading configuration directory '%s'\n", config);
}
}
for (int i = 0; i < filenum; i++) {
char filename_tmp[PATH_MAX];
if (snprintf(filename_tmp, path_max, "%s/%s", config, files[i]->d_name) >= path_max) {
continue;
}
if (bearssl_read_certs(&btas, filename_tmp) == 0) {
if (debug) fprintf(stderr, "error reading cert file '%s'\n", filename_tmp);
}
free(files[i]);
}
free(files);
stop_search:
br_ssl_client_init_full(&sc, &xc, btas.ta, btas.n);
br_ssl_engine_set_buffer(&sc.eng, iobuf, sizeof iobuf, 1);

View File

@ -4,7 +4,6 @@
#include <string.h>
#include "read_certs.h"
#include "mmap_file.h"
struct append_dn_status {
uint8_t *dn;
@ -104,21 +103,22 @@ static void push_x509(void *dest_ctx, const void *src, size_t len)
/*
* Reads certs from file if set, otherwise from default location.
*/
size_t bearssl_read_certs(struct trust_anchors *tas, const char *file)
size_t bearssl_read_certs(struct trust_anchors *tas, FILE *file)
{
const char *cert_path = file ? file : getenv("CA_CERT_SSL_FILE");
if (cert_path == NULL) {
cert_path = "/etc/ssl/certs.pem";
}
size_t rv = 0;
struct mmap_file cert_map = create_mmap_from_file(cert_path, PROT_READ);
if (ERROR_MMAP(cert_map)) {
perror("create_mmap_from_file()");
return 0;
}
if (file == NULL) {
const char *cert_path = getenv("CA_CERT_SSL_FILE");
if (cert_path == NULL) {
cert_path = "/etc/ssl/certs.pem";
}
off_t len = cert_map.size;
uint8_t *data = cert_map.data;
file = fopen(cert_path, "re");
if (file == NULL) {
perror("fopen()");
return rv;
}
}
br_pem_decoder_context pem;
br_x509_decoder_context x509;
@ -127,10 +127,20 @@ size_t bearssl_read_certs(struct trust_anchors *tas, const char *file)
struct append_dn_status dn_status;
while (len > 0) {
size_t pushed = br_pem_decoder_push(&pem, data, len);
data += pushed;
uint8_t data[512];
uint8_t *datap;
size_t len = 0;
while (1) {
if (len == 0) {
len = fread(data, 1, 512, file);
if (len == 0) {
break;
}
datap = data;
}
size_t pushed = br_pem_decoder_push(&pem, datap, len);
len -= pushed;
datap += pushed;
switch(br_pem_decoder_event(&pem)) {
const char *name;
@ -179,7 +189,7 @@ size_t bearssl_read_certs(struct trust_anchors *tas, const char *file)
.e = malloc(k.elen), .elen = k.elen};
if (rsa.n == NULL || rsa.e == NULL) {
perror("malloc()");
return 0;
goto out;
}
memcpy(rsa.n, k.n, k.nlen);
memcpy(rsa.e, k.e, k.elen);
@ -193,7 +203,7 @@ size_t bearssl_read_certs(struct trust_anchors *tas, const char *file)
.q = malloc(k.qlen), .qlen = k.qlen};
if (ec.q == NULL) {
perror("malloc()");
return 0;
goto out;
}
memcpy(ec.q, k.q, k.qlen);
@ -205,12 +215,15 @@ size_t bearssl_read_certs(struct trust_anchors *tas, const char *file)
ta.pkey = new_key;
if (append_ta(tas, ta) == -1) {
return 0;
goto out;
}
}
break;
}
}
return tas->n;
rv = tas->n;
out:
fclose(file);
return rv;
}

View File

@ -12,6 +12,6 @@ struct trust_anchors {
void bearssl_read_certs_help(FILE *);
void bearssl_free_certs(struct trust_anchors);
size_t bearssl_read_certs(struct trust_anchors *, const char *);
size_t bearssl_read_certs(struct trust_anchors *, FILE *);
#endif // __READ_CERTS_H_