[gnutls-dev] [PATCH] error handling large CA files
Ian Peters
itp@ximian.com
Tue Mar 11 22:51:01 2003
--=-BrvIWqqp9XCcFMLzkM68
Content-Type: text/plain
Content-Transfer-Encoding: 7bit
In lib/gnutls_x509.c, the functions read_cert_file, read_ca_file, and
read_key_file all read into a stack-allocated buffer of MAX_FILE_SIZE,
which is defined as 1024*100. The default CA file that comes with most
web browsers exceeds this (it is closer to 245k). This means that the
file is truncated, and parse_pem_cert_mem only sees part of the file,
resulting in only some of the trusted certificates being loaded.
Because of the pem file format, this is not a fatal error, and program
execution continues, but some certificates that should be trusted are
not.
The attached patch fixes these three functions to read passed file into
a heap-allocated buffer, parse the memory, and then free the buffer.
You'll probably want to tweak things to fit into gnutls better
stylistically.
Ian
--=-BrvIWqqp9XCcFMLzkM68
Content-Disposition: attachment; filename=gnutls-0.8.4-large-ca-file.patch
Content-Type: text/x-patch; name=gnutls-0.8.4-large-ca-file.patch; charset=UTF-8
Content-Transfer-Encoding: 7bit
diff -r -u gnutls-0.8.4/lib/gnutls_x509.c gnutls-0.8.4.new/lib/gnutls_x509.c
--- gnutls-0.8.4/lib/gnutls_x509.c 2003-02-04 07:52:24.000000000 -0500
+++ gnutls-0.8.4.new/lib/gnutls_x509.c 2003-03-11 15:01:29.000000000 -0500
@@ -1602,26 +1602,66 @@
}
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+extern int errno;
+static int read_file(const char *filename, char **data, int *len)
+{
+ int fd;
+ struct stat s;
+ char *buf;
+ unsigned int bytes_read = 0;
+
+ if ((fd = open( filename, O_RDONLY)) < 0) {
+ gnutls_assert();
+ return GNUTLS_E_FILE_ERROR;
+ }
+
+ if ((fstat( fd, &s)) < 0) {
+ gnutls_assert();
+ close(fd);
+ return GNUTLS_E_FILE_ERROR;
+ }
+
+ buf = gnutls_malloc(s.st_size + 1);
+ buf[s.st_size] = 0;
+
+ while (bytes_read < s.st_size) {
+ int ret;
+ ret = read( fd, buf + bytes_read, s.st_size - bytes_read);
+ if (ret < 0 && errno != EINTR && errno != EAGAIN) {
+ gnutls_assert();
+ gnutls_free(buf);
+ close(fd);
+ return GNUTLS_E_FILE_ERROR;
+ }
+ bytes_read += ret;
+ }
+
+ *data = buf;
+ *len = s.st_size + 1;
+ return 0;
+}
+
/* Reads a certificate file
*/
static int read_cert_file(gnutls_certificate_credentials res, const char *certfile,
gnutls_x509_certificate_format type)
{
int siz;
- char x[MAX_FILE_SIZE];
- FILE *fd1;
-
- fd1 = fopen(certfile, "rb");
- if (fd1 == NULL)
- return GNUTLS_E_FILE_ERROR;
-
- siz = fread(x, 1, sizeof(x)-1, fd1);
- fclose(fd1);
-
- x[siz] = 0;
+ char *x;
+ int ret;
- return read_cert_mem( res, x, siz, type);
+ if ((ret = read_file( certfile, &x, &siz)) < 0) {
+ gnutls_assert();
+ return ret;
+ }
+ ret = read_cert_mem( res, x, siz, type);
+ gnutls_free(x);
+ return ret;
}
/* Reads a base64 encoded CA file (file contains multiple certificate
@@ -1631,21 +1671,17 @@
gnutls_x509_certificate_format type)
{
int siz;
- char x[MAX_FILE_SIZE];
- FILE *fd1;
+ char *x;
+ int ret;
- fd1 = fopen(cafile, "rb");
- if (fd1 == NULL) {
+ if ((ret = read_file( cafile, &x, &siz)) < 0) {
gnutls_assert();
- return GNUTLS_E_FILE_ERROR;
+ return ret;
}
- siz = fread(x, 1, sizeof(x)-1, fd1);
- fclose(fd1);
-
- x[siz] = 0;
-
- return read_ca_mem( res, x, siz, type);
+ ret = read_ca_mem( res, x, siz, type);
+ gnutls_free(x);
+ return ret;
}
@@ -1656,19 +1692,17 @@
gnutls_x509_certificate_format type)
{
int siz;
- char x[MAX_FILE_SIZE];
- FILE *fd2;
-
- fd2 = fopen(keyfile, "rb");
- if (fd2 == NULL)
- return GNUTLS_E_FILE_ERROR;
-
- siz = fread(x, 1, sizeof(x)-1, fd2);
- fclose(fd2);
+ char *x;
+ int ret;
- x[siz] = 0;
+ if ((ret = read_file( keyfile, &x, &siz)) < 0) {
+ gnutls_assert();
+ return ret;
+ }
- return read_key_mem( res, x, siz, type);
+ ret = read_key_mem( res, x, siz, type);
+ gnutls_free(x);
+ return ret;
}
/**
--=-BrvIWqqp9XCcFMLzkM68--