[mod_openssl,mbedtls,gnutls,nss] fdevent_load_file

employ fdevent_load_file() to load CRL, X509 cert, and private key files
into memory
This commit is contained in:
Glenn Strauss 2020-07-02 17:20:29 -04:00
parent cc04468762
commit 0ad57da55b
4 changed files with 99 additions and 148 deletions

View File

@ -214,10 +214,6 @@ static void elogf(log_error_st * const errh,
* https://gitlab.com/gnutls/gnutls/-/issues/1002
* https://gitlab.com/gnutls/gnutls/-/merge_requests/1270
*/
#include <sys/stat.h>
#include <fcntl.h>
#include <limits.h>
#include "fdevent.h"
static int
mod_gnutls_load_file (const char * const fn, gnutls_datum_t * const d, log_error_st *errh)
{
@ -227,49 +223,12 @@ mod_gnutls_load_file (const char * const fn, gnutls_datum_t * const d, log_error
elogf(errh, __FILE__, __LINE__, rc, "%s() %s", __func__, fn);
return rc;
#else
int fd = -1;
unsigned int sz = 0;
char *buf = NULL;
do {
fd = fdevent_open_cloexec(fn, 1, O_RDONLY, 0); /*(1: follows symlinks)*/
if (fd < 0) break;
struct stat st;
if (0 != fstat(fd, &st)) break;
if (st.st_size >= UINT_MAX) { /*(file too large for gnutls_datum_t)*/
errno = EOVERFLOW;
break;
}
sz = (unsigned int)st.st_size;
buf = gnutls_malloc(sz+1); /*(+1 trailing '\0' for gnutls_load_file())*/
if (NULL == buf) break;
ssize_t rd = 0;
unsigned int off = 0;
do {
rd = read(fd, buf+off, sz-off);
} while (rd > 0 ? (off += (unsigned int)rd) != sz : errno == EINTR);
if (off != sz) { /*(file truncated?)*/
if (rd >= 0) errno = EIO;
break;
}
buf[sz] = '\0';
d->data = (unsigned char *)buf;
d->size = sz;
close(fd);
return 0;
} while (0);
int errnum = errno;
log_perror(errh, __FILE__, __LINE__, "%s() %s", __func__, fn);
if (fd >= 0) close(fd);
if (buf) {
gnutls_memset(buf, 0, sz);
gnutls_free(buf);
}
errno = errnum;
return GNUTLS_E_FILE_ERROR;
off_t dlen = 512*1024*1024;/*(arbitrary limit: 512 MB file; expect < 1 MB)*/
char *data = fdevent_load_file(fn, &dlen, errh, gnutls_malloc, gnutls_free);
if (NULL == data) return GNUTLS_E_FILE_ERROR;
d->data = (unsigned char *)data;
d->size = (unsigned int)dlen;
return 0;
#endif
}

View File

@ -87,6 +87,7 @@
#include "http_header.h"
#include "log.h"
#include "plugin.h"
#include "safe_memclear.h"
typedef struct {
/* SNI per host: with COMP_SERVER_SOCKET, COMP_HTTP_SCHEME, COMP_HTTP_HOST */
@ -753,6 +754,70 @@ mod_mbedtls_conf_verify (handler_ctx *hctx, mbedtls_ssl_config *ssl_ctx)
}
/* mbedTLS interfaces are generally excellent. mbedTLS convenience interfaces
* to read CRLs, X509 certs, and private keys are uniformly paranoid about
* clearing memory. At the moment, stdio routines fopen(), fread(), fclose()
* are used for portability, but without setvbuf(stream, NULL, _IOLBF, 0),
* again for portability, since setvbuf() is not necessarily available. Since
* stdio buffers by default, use our own funcs to read files without buffering.
* mbedtls_pk_load_file() includes trailing '\0' in size when contents in PEM
* format, so do the same with the value returned from fdevent_load_file().
*/
static int
mod_mbedtls_x509_crl_parse_file (mbedtls_x509_crl *chain, const char *fn)
{
int rc = MBEDTLS_ERR_X509_FILE_IO_ERROR;
off_t dlen = 512*1024*1024;/*(arbitrary limit: 512 MB file; expect < 1 MB)*/
char *data = fdevent_load_file(fn, &dlen, NULL, malloc, free);
if (NULL == data) return rc;
rc = mbedtls_x509_crl_parse(chain, (unsigned char *)data, (size_t)dlen+1);
if (dlen) safe_memclear(data, (size_t)dlen);
free(data);
return rc;
}
static int
mod_mbedtls_x509_crt_parse_file (mbedtls_x509_crt *chain, const char *fn)
{
int rc = MBEDTLS_ERR_X509_FILE_IO_ERROR;
off_t dlen = 512*1024*1024;/*(arbitrary limit: 512 MB file; expect < 1 MB)*/
char *data = fdevent_load_file(fn, &dlen, NULL, malloc, free);
if (NULL == data) return rc;
rc = mbedtls_x509_crt_parse(chain, (unsigned char *)data, (size_t)dlen+1);
if (dlen) safe_memclear(data, (size_t)dlen);
free(data);
return rc;
}
static int
mod_mbedtls_pk_parse_keyfile (mbedtls_pk_context *ctx, const char *fn, const char *pwd)
{
int rc = MBEDTLS_ERR_PK_FILE_IO_ERROR;
off_t dlen = 512*1024*1024;/*(arbitrary limit: 512 MB file; expect < 1 MB)*/
char *data = fdevent_load_file(fn, &dlen, NULL, malloc, free);
if (NULL == data) return rc;
rc = mbedtls_pk_parse_key(ctx, (unsigned char *)data, (size_t)dlen+1,
(const unsigned char *)pwd,
pwd ? strlen(pwd) : 0);
if (dlen) safe_memclear(data, (size_t)dlen);
free(data);
return rc;
}
static void *
network_mbedtls_load_pemfile (server *srv, const buffer *pemfile, const buffer *privkey)
{
@ -761,7 +826,7 @@ network_mbedtls_load_pemfile (server *srv, const buffer *pemfile, const buffer *
int rc;
mbedtls_x509_crt_init(&ssl_pemfile_x509); /* init cert structure */
rc = mbedtls_x509_crt_parse_file(&ssl_pemfile_x509, pemfile->ptr);
rc = mod_mbedtls_x509_crt_parse_file(&ssl_pemfile_x509, pemfile->ptr);
if (0 != rc) {
elogf(srv->errh, __FILE__, __LINE__, rc,
"PEM file cert read failed (%s)", pemfile->ptr);
@ -769,7 +834,7 @@ network_mbedtls_load_pemfile (server *srv, const buffer *pemfile, const buffer *
}
mbedtls_pk_init(&ssl_pemfile_pkey); /* init private key context */
rc = mbedtls_pk_parse_keyfile(&ssl_pemfile_pkey, privkey->ptr, NULL);
rc = mod_mbedtls_pk_parse_keyfile(&ssl_pemfile_pkey, privkey->ptr, NULL);
if (0 != rc) {
elogf(srv->errh, __FILE__, __LINE__, rc,
"PEM file private key read failed %s", privkey->ptr);
@ -837,7 +902,7 @@ mod_mbedtls_acme_tls_1 (handler_ctx *hctx)
ssl_pemfile_x509 = malloc(sizeof(*ssl_pemfile_x509));
force_assert(ssl_pemfile_x509);
mbedtls_x509_crt_init(ssl_pemfile_x509); /* init cert structure */
rc = mbedtls_x509_crt_parse_file(ssl_pemfile_x509, b->ptr);
rc = mod_mbedtls_x509_crt_parse_file(ssl_pemfile_x509, b->ptr);
if (0 != rc) {
elogf(errh, __FILE__, __LINE__, rc,
"Failed to load acme-tls/1 pemfile: %s", b->ptr);
@ -849,7 +914,7 @@ mod_mbedtls_acme_tls_1 (handler_ctx *hctx)
ssl_pemfile_pkey = malloc(sizeof(*ssl_pemfile_pkey));
force_assert(ssl_pemfile_pkey);
mbedtls_pk_init(ssl_pemfile_pkey); /* init private key context */
rc = mbedtls_pk_parse_keyfile(ssl_pemfile_pkey, b->ptr, NULL);
rc = mod_mbedtls_pk_parse_keyfile(ssl_pemfile_pkey, b->ptr, NULL);
if (0 != rc) {
elogf(errh, __FILE__, __LINE__, rc,
"Failed to load acme-tls/1 pemfile: %s", b->ptr);
@ -1533,7 +1598,8 @@ SETDEFAULTS_FUNC(mod_mbedtls_set_defaults)
mbedtls_x509_crt *cacert = calloc(1, sizeof(*cacert));
force_assert(cacert);
mbedtls_x509_crt_init(cacert);
int rc = mbedtls_x509_crt_parse_file(cacert, cpv->v.b->ptr);
int rc =
mod_mbedtls_x509_crt_parse_file(cacert, cpv->v.b->ptr);
if (0 == rc) {
cpv->vtype = T_CONFIG_LOCAL;
cpv->v.v = cacert;
@ -1552,7 +1618,8 @@ SETDEFAULTS_FUNC(mod_mbedtls_set_defaults)
mbedtls_x509_crl *crl = malloc(sizeof(*crl));
force_assert(crl);
mbedtls_x509_crl_init(crl);
int rc = mbedtls_x509_crl_parse_file(crl, cpv->v.b->ptr);
int rc =
mod_mbedtls_x509_crl_parse_file(crl, cpv->v.b->ptr);
if (0 == rc) {
cpv->vtype = T_CONFIG_LOCAL;
cpv->v.v = crl;

View File

@ -330,57 +330,16 @@ mod_nss_io_dtor (PRFileDesc *ssl)
}
#include <sys/stat.h>
#include <fcntl.h>
#include <limits.h>
#include "fdevent.h"
static int
mod_nss_load_file (const char * const fn, SECItem * const d, log_error_st *errh)
{
int fd = -1;
unsigned int sz = 0;
char *buf = NULL;
do {
fd = fdevent_open_cloexec(fn, 1, O_RDONLY, 0); /*(1: follows symlinks)*/
if (fd < 0) break;
struct stat st;
if (0 != fstat(fd, &st)) break;
if (st.st_size >= UINT_MAX) { /*(file too large for SECItem)*/
errno = EOVERFLOW;
break;
}
sz = (unsigned int)st.st_size;
buf = PORT_Alloc(sz+1); /*(+1 trailing '\0' for str funcs on PEM)*/
if (NULL == buf) break;
ssize_t rd = 0;
unsigned int off = 0;
do {
rd = read(fd, buf+off, sz-off);
} while (rd > 0 ? (off += (unsigned int)rd) != sz : errno == EINTR);
if (off != sz) { /*(file truncated?)*/
if (rd >= 0) errno = EIO;
break;
}
buf[sz] = '\0';
d->type = siBuffer;
d->data = (unsigned char *)buf;
d->len = sz;
close(fd);
return 0;
} while (0);
int errnum = errno;
log_perror(errh, __FILE__, __LINE__, "%s() %s", __func__, fn);
if (fd >= 0) close(fd);
if (buf) {
safe_memclear(buf, sz);
PORT_Free(buf); /* safe_memclear() is safer than PORT_ZFree() */
}
errno = errnum;
return -1;
off_t dlen = 512*1024*1024;/*(arbitrary limit: 512 MB file; expect < 1 MB)*/
char *data = fdevent_load_file(fn, &dlen, errh, PORT_Alloc, PORT_Free);
if (NULL == data) return -1;
d->type = siBuffer;
d->data = (unsigned char *)data;
d->len = (unsigned int)dlen;
return 0;
}

View File

@ -1403,55 +1403,21 @@ mod_openssl_load_stapling_file (const char *file, log_error_st *errh, buffer *b)
* typically the same size with the signature and dates refreshed.
*/
#ifdef BORINGSSL_API_VERSION
#if defined(BORINGSSL_API_VERSION) \
|| defined(WOLFSSL_VERSION)
/* load raw .der file */
/* (similar to mod_gnutls.c:mod_gnutls_load_file(), but some differences) */
int fd = -1;
uint32_t sz = 0;
char *buf = NULL;
do {
fd = fdevent_open_cloexec(file,1,O_RDONLY,0); /*(1: follows symlinks)*/
if (fd < 0) break;
struct stat st;
if (0 != fstat(fd, &st)) break;
if (st.st_size == 0) break;
if (st.st_size >= UINT32_MAX) { /*(file too large for buffer uint32_t)*/
errno = EOVERFLOW;
break;
}
sz = (uint32_t)st.st_size;
buf = malloc(sz+1); /*(+1 trailing '\0')*/
if (NULL == buf) break;
ssize_t rd = 0;
unsigned int off = 0;
do {
rd = read(fd, buf+off, sz-off);
} while (rd > 0 ? (off += (unsigned int)rd) != sz : errno == EINTR);
if (off != sz) { /*(file truncated?)*/
if (rd >= 0) errno = EIO;
break;
}
if (NULL == b) b = buffer_init();
buffer_copy_string_len(b, buf, sz);
memset(buf, 0, sz);
free(buf);
close(fd);
return b;
} while (0);
int errnum = errno;
log_perror(errh, __FILE__, __LINE__, "%s() %s", __func__, file);
if (fd >= 0) close(fd);
if (buf) {
memset(buf, 0, sz);
free(buf);
}
errno = errnum;
return NULL;;
off_t dlen = 1*1024*1024;/*(arbitrary limit: 1 MB file; expect < 1 KB)*/
char *data = fdevent_load_file(file, &dlen, errh, malloc, free);
if (NULL == data) return NULL;
if (NULL == b)
b = buffer_init();
else if (b->ptr)
free(b->ptr);
b->ptr = data;
b->used = (uint32_t)dlen;
b->size = (uint32_t)dlen+1;
return b;
#else