diff options
-rw-r--r-- | .gitignore | 7 | ||||
-rw-r--r-- | bootstrap.conf | 2 | ||||
-rw-r--r-- | lib/Makefile.am | 2 | ||||
-rw-r--r-- | lib/libgnutls.map | 5 | ||||
-rw-r--r-- | lib/pathbuf.c | 146 | ||||
-rw-r--r-- | lib/pathbuf.h | 49 | ||||
-rw-r--r-- | lib/system.h | 6 | ||||
-rw-r--r-- | lib/system/certs.c | 43 | ||||
-rw-r--r-- | lib/x509/verify-high2.c | 126 | ||||
-rw-r--r-- | tests/Makefile.am | 6 | ||||
-rw-r--r-- | tests/pathbuf.c | 66 |
11 files changed, 390 insertions, 68 deletions
diff --git a/.gitignore b/.gitignore index 288efb9c59..597530a6a3 100644 --- a/.gitignore +++ b/.gitignore @@ -414,6 +414,7 @@ tests/gnutls-strcodes tests/gnutls_ext_raw_parse tests/gnutls_ext_raw_parse_dtls tests/gnutls_hmac_fast +tests/gnutls_ktls tests/gnutls_ocsp_resp_list_import2 tests/gnutls_record_overhead tests/gnutls_session_set_id @@ -452,6 +453,7 @@ tests/key-usage-rsa tests/keygen tests/keylog-env tests/keylog-func +tests/ktls_keyupdate tests/libpkcs11mock1.la tests/libpkcs11mock2.la tests/libutils.la @@ -545,6 +547,7 @@ tests/openpgp-keyring tests/openpgpself tests/openssl tests/parse_ca +tests/pathbuf tests/pathlen/Makefile tests/pathlen/Makefile.in tests/pcert-list @@ -625,6 +628,7 @@ tests/random-art tests/rawpk-api tests/record-pad tests/record-retvals +tests/record-sendfile tests/record-sizes tests/record-sizes-range tests/record-timeouts @@ -918,9 +922,6 @@ tests/x509sign-verify-rsa tests/x509sign-verify2 tests/x509signself tests/xts-key-check -tests/gnutls_ktls -tests/record-sendfile -tests/ktls_keyupdate *.tmp tmp-* *.trs diff --git a/bootstrap.conf b/bootstrap.conf index ad8d7cd51e..c4d1fe06b2 100644 --- a/bootstrap.conf +++ b/bootstrap.conf @@ -27,7 +27,7 @@ required_submodules="tests/suite/tls-fuzzer/python-ecdsa tests/suite/tls-fuzzer/ # Those modules are common to lib/ and src/. common_modules=" -alloca attribute byteswap c-ctype c-strcase canonicalize-lgpl explicit_bzero fopen-gnu func getline gettext-h gettimeofday hash hash-pjw-bare arpa_inet inet_ntop inet_pton intprops linkedhash-list lock memmem-simple minmax netdb netinet_in read-file secure_getenv setsockopt snprintf stdint stpcpy strcase strdup-posix strndup strtok_r strverscmp sys_socket sys_stat sys_types threadlib time_r tls unistd valgrind-tests vasprintf verify vsnprintf xalloc-oversized +alloca attribute byteswap c-ctype c-strcase canonicalize-lgpl explicit_bzero fopen-gnu func getline gettext-h gettimeofday hash hash-pjw-bare arpa_inet inet_ntop inet_pton intprops linkedhash-list lock memmem-simple minmax netdb netinet_in pathmax read-file secure_getenv setsockopt snprintf stdint stpcpy strcase strdup-posix strndup strtok_r strverscmp sys_socket sys_stat sys_types threadlib time_r tls unistd valgrind-tests vasprintf verify vsnprintf xalloc-oversized " gnulib_modules=" $common_modules dirname-lgpl extensions gendocs havelib ldd lib-msvc-compat lib-symbol-versions maintainer-makefile manywarnings pmccabe2html warnings diff --git a/lib/Makefile.am b/lib/Makefile.am index fc83a37333..6d4e8d225a 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -83,7 +83,7 @@ COBJECTS = range.c record.c compress.c debug.c cipher.c gthreads.h handshake-tls cert-session.c handshake-checks.c dtls-sw.c dh-primes.c openpgp_compat.c \ crypto-selftests.c crypto-selftests-pk.c secrets.c extv.c extv.h \ hello_ext_lib.c hello_ext_lib.h ocsp-api.c stek.c cert-cred-rawpk.c \ - iov.c iov.h system/ktls.c system/ktls.h + iov.c iov.h system/ktls.c system/ktls.h pathbuf.c pathbuf.h if ENABLE_GOST COBJECTS += vko.c diff --git a/lib/libgnutls.map b/lib/libgnutls.map index 31cbb90489..72e425c3a0 100644 --- a/lib/libgnutls.map +++ b/lib/libgnutls.map @@ -1514,4 +1514,9 @@ GNUTLS_PRIVATE_3_4 { _gnutls_crypto_register_cipher; # needed by tests/tls12-rehandshake-cert-ticket _gnutls_session_ticket_disable_server; + # needed by tests/pathbuf + _gnutls_pathbuf_init; + _gnutls_pathbuf_append; + _gnutls_pathbuf_truncate; + _gnutls_pathbuf_deinit; } GNUTLS_3_4; diff --git a/lib/pathbuf.c b/lib/pathbuf.c new file mode 100644 index 0000000000..a5d6316fcd --- /dev/null +++ b/lib/pathbuf.c @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2010-2022 Free Software Foundation, Inc. + * Copyright (C) 2022 Red Hat, Inc. + * + * Author: Daiki Ueno + * + * This file is part of GnuTLS. + * + * The GnuTLS is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/> + * + */ + +#include "config.h" + +#include "pathbuf.h" +#include "gnutls_int.h" +#include <limits.h> +#include "intprops.h" + +static int +pathbuf_reserve(struct gnutls_pathbuf_st *buffer, size_t to_add) +{ + size_t len; + char *ptr; + + len = buffer->len; + + if (INT_ADD_OVERFLOW(len, to_add)) { + return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); + } + len += to_add; + + /* NUL terminator. */ + if (INT_ADD_OVERFLOW(len, 1)) { + return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); + } + len++; + + if (len <= buffer->cap) { + return 0; + } + + if (buffer->ptr == buffer->base) { + ptr = gnutls_strdup(buffer->ptr); + if (!ptr) { + return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); + } + buffer->ptr = ptr; + } + + ptr = gnutls_realloc(buffer->ptr, len); + if (!ptr) { + return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); + } + + buffer->ptr = ptr; + buffer->cap = len; + + return 0; +} + +int +_gnutls_pathbuf_init(struct gnutls_pathbuf_st *buffer, const char *base) +{ + size_t len; + int ret; + + memset(buffer, 0, sizeof(*buffer)); + buffer->cap = sizeof(buffer->base); + buffer->ptr = buffer->base; + + len = strlen(base); + + ret = pathbuf_reserve(buffer, len); + if (ret < 0) { + return ret; + } + + strcpy(buffer->ptr, base); + buffer->len = len; + + return 0; +} + +int +_gnutls_pathbuf_append(struct gnutls_pathbuf_st *buffer, const char *component) +{ + size_t len; + char *p; + int ret; + + len = strlen(component); + + /* Path separator. */ + if (INT_ADD_OVERFLOW(len, 1)) { + return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); + } + len++; + + ret = pathbuf_reserve(buffer, len); + if (ret < 0) { + return ret; + } + + p = stpcpy(&buffer->ptr[buffer->len], "/"); + strcpy(p, component); + + /* Overflow is already checked in the call to pathbuf_reserve + * above. + */ + buffer->len += len; + + return 0; +} + +int +_gnutls_pathbuf_truncate(struct gnutls_pathbuf_st *buffer, size_t len) +{ + if (len > buffer->len) { + return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); + } + buffer->len = len; + buffer->ptr[len] = '\0'; + return 0; +} + +void +_gnutls_pathbuf_deinit(struct gnutls_pathbuf_st *buffer) +{ + if (buffer->ptr != buffer->base) { + gnutls_free(buffer->ptr); + } + memset(buffer, 0, sizeof(*buffer)); +} + diff --git a/lib/pathbuf.h b/lib/pathbuf.h new file mode 100644 index 0000000000..2739e4dd29 --- /dev/null +++ b/lib/pathbuf.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2010-2022 Free Software Foundation, Inc. + * Copyright (C) 2022 Red Hat, Inc. + * + * Author: Daiki Ueno + * + * This file is part of GnuTLS. + * + * The GnuTLS is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/> + * + */ + +#ifndef GNUTLS_LIB_PATHBUF_H +#define GNUTLS_LIB_PATHBUF_H + +#include "pathmax.h" +#define GNUTLS_PATH_MAX PATH_MAX + +struct gnutls_pathbuf_st { + char base[GNUTLS_PATH_MAX + 1]; + char *ptr; /* API */ + size_t len; /* API: NOT including NUL */ + size_t cap; /* including NUL */ +}; + +/* Initialize BUFFER with the content BASE. */ +int _gnutls_pathbuf_init(struct gnutls_pathbuf_st *buffer, const char *base); + +/* Append COMPONENT to BUFFER, separated with a "/". */ +int _gnutls_pathbuf_append(struct gnutls_pathbuf_st *buffer, const char *component); + +/* Truncate the length of BUFFER to LEN. */ +int _gnutls_pathbuf_truncate(struct gnutls_pathbuf_st *buffer, size_t len); + +/* Deinitialize BUFFER. */ +void _gnutls_pathbuf_deinit(struct gnutls_pathbuf_st *buffer); + +#endif /* GNUTLS_LIB_PATHBUF_H */ diff --git a/lib/system.h b/lib/system.h index e15c8cd33d..13cbf1a9fe 100644 --- a/lib/system.h +++ b/lib/system.h @@ -44,11 +44,7 @@ extern CertEnumCRLsInStoreFunc pCertEnumCRLsInStore; #include <sys/uio.h> /* for writev */ #endif -#ifdef _POSIX_PATH_MAX -# define GNUTLS_PATH_MAX _POSIX_PATH_MAX -#else -# define GNUTLS_PATH_MAX 256 -#endif +#include "pathbuf.h" int system_errno(gnutls_transport_ptr_t); diff --git a/lib/system/certs.c b/lib/system/certs.c index c06b82354b..e155bd9389 100644 --- a/lib/system/certs.c +++ b/lib/system/certs.c @@ -217,31 +217,42 @@ int add_system_trust(gnutls_x509_trust_list_t list, unsigned int tl_flags, # if defined(ANDROID) || defined(__ANDROID__) # define DEFAULT_TRUST_STORE_DIR "/system/etc/security/cacerts/" +# define DEFAULT_REVOCATION_DIR "/data/misc/keychain/cacerts-removed" + static int load_revoked_certs(gnutls_x509_trust_list_t list, unsigned type) { DIR *dirp; struct dirent *d; int ret; int r = 0; - char path[GNUTLS_PATH_MAX]; + struct gnutls_pathbuf_st pathbuf; - dirp = opendir("/data/misc/keychain/cacerts-removed/"); + dirp = opendir(DEFAULT_REVOCATION_DIR); if (dirp != NULL) { - do { - d = readdir(dirp); - if (d != NULL && d->d_type == DT_REG) { - snprintf(path, sizeof(path), - "/data/misc/keychain/cacerts-removed/%s", - d->d_name); - - ret = - gnutls_x509_trust_list_remove_trust_file - (list, path, type); - if (ret >= 0) - r += ret; - } + size_t base_len; + + ret = _gnutls_pathbuf_init(&pathbuf, DEFAULT_REVOCATION_DIR); + if (ret < 0) { + return 0; + } + + base_len = pathbuf.len; + while ((d = readdir(dirp)) != NULL) { + if (d->d_type != DT_REG) { + continue; + } + ret = _gnutls_pathbuf_append(&pathbuf, d->d_name); + if (ret < 0) { + continue; + } + ret = gnutls_x509_trust_list_remove_trust_file + (list, pathbuf.ptr, type); + if (ret >= 0) { + r += ret; + } + (void)_gnutls_pathbuf_truncate(&pathbuf, base_len); } - while (d != NULL); + _gnutls_pathbuf_deinit(&pathbuf); closedir(dirp); } diff --git a/lib/x509/verify-high2.c b/lib/x509/verify-high2.c index eaaaa8b897..e69b1567c4 100644 --- a/lib/x509/verify-high2.c +++ b/lib/x509/verify-high2.c @@ -393,7 +393,7 @@ int load_dir_certs(const char *dirname, { int ret; int r = 0; - char path[GNUTLS_PATH_MAX]; + struct gnutls_pathbuf_st pathbuf; #if !defined(_WIN32) || !defined(_UNICODE) DIR *dirp; @@ -401,29 +401,44 @@ int load_dir_certs(const char *dirname, dirp = opendir(dirname); if (dirp != NULL) { + size_t base_len; + + ret = _gnutls_pathbuf_init(&pathbuf, dirname); + if (ret < 0) { + return r; + } + + base_len = pathbuf.len; while ((d = readdir(dirp)) != NULL) { #ifdef _DIRENT_HAVE_D_TYPE - if (d->d_type == DT_REG || d->d_type == DT_LNK || d->d_type == DT_UNKNOWN) + switch (d->d_type) { + case DT_REG: + case DT_LNK: + case DT_UNKNOWN: + break; + default: + continue; + } #endif - { - snprintf(path, sizeof(path), "%s/%s", - dirname, d->d_name); - - if (crl != 0) { - ret = - gnutls_x509_trust_list_add_trust_file - (list, NULL, path, type, tl_flags, - tl_vflags); - } else { - ret = - gnutls_x509_trust_list_add_trust_file - (list, path, NULL, type, tl_flags, - tl_vflags); - } - if (ret >= 0) - r += ret; + ret = _gnutls_pathbuf_append(&pathbuf, d->d_name); + if (ret < 0) { + continue; + } + if (crl != 0) { + ret = gnutls_x509_trust_list_add_trust_file + (list, NULL, pathbuf.ptr, type, tl_flags, + tl_vflags); + } else { + ret = gnutls_x509_trust_list_add_trust_file + (list, pathbuf.ptr, NULL, type, tl_flags, + tl_vflags); } + if (ret >= 0) { + r += ret; + } + (void)_gnutls_pathbuf_truncate(&pathbuf, base_len); } + _gnutls_pathbuf_deinit(&pathbuf); closedir(dirp); } #else /* _WIN32 */ @@ -432,41 +447,70 @@ int load_dir_certs(const char *dirname, struct _tdirent *d; gnutls_datum_t utf16 = {NULL, 0}; +#undef UCS2_ENDIAN #ifdef WORDS_BIGENDIAN - r = _gnutls_utf8_to_ucs2(dirname, strlen(dirname), &utf16, 1); +#define UCS2_ENDIAN 1 #else - r = _gnutls_utf8_to_ucs2(dirname, strlen(dirname), &utf16, 0); +#define UCS2_ENDIAN 0 #endif - if (r < 0) - return gnutls_assert_val(r); + + ret = _gnutls_utf8_to_ucs2(dirname, strlen(dirname), &utf16, UCS2_ENDIAN); + if (ret < 0) { + return gnutls_assert_val(ret); + } dirp = _topendir((_TCHAR*)utf16.data); gnutls_free(utf16.data); if (dirp != NULL) { + size_t base_len; + + ret = _gnutls_pathbuf_init(&pathbuf, dirname); + if (ret < 0) { + return r; + } + + base_len = pathbuf.len; while ((d = _treaddir(dirp)) != NULL) { + gnutls_datum_t utf8 = {NULL, 0}; #ifdef _DIRENT_HAVE_D_TYPE - if (d->d_type == DT_REG || d->d_type == DT_LNK || d->d_type == DT_UNKNOWN) + switch (d->d_type) { + case DT_REG: + case DT_LNK: + case DT_UNKNOWN: + break; + default: + continue; + } #endif - { - snprintf(path, sizeof(path), "%s/%ls", - dirname, d->d_name); - - if (crl != 0) { - ret = - gnutls_x509_trust_list_add_trust_file - (list, NULL, path, type, tl_flags, - tl_vflags); - } else { - ret = - gnutls_x509_trust_list_add_trust_file - (list, path, NULL, type, tl_flags, - tl_vflags); - } - if (ret >= 0) - r += ret; + ret = _gnutls_ucs2_to_utf8(d->d_name, + d->d_namlen * sizeof(d->d_name[0]), + &utf8, + UCS2_ENDIAN); + if (ret < 0) { + continue; + } + ret = _gnutls_pathbuf_append(&pathbuf, utf8.data); + gnutls_free(utf8.data); + if (ret < 0) { + continue; + } + + if (crl != 0) { + ret = gnutls_x509_trust_list_add_trust_file + (list, NULL, pathbuf.ptr, type, tl_flags, + tl_vflags); + } else { + ret = gnutls_x509_trust_list_add_trust_file + (list, pathbuf.ptr, NULL, type, tl_flags, + tl_vflags); } + if (ret >= 0) + r += ret; + (void)_gnutls_pathbuf_truncate(&pathbuf, base_len); } + _gnutls_pathbuf_deinit(&pathbuf); _tclosedir(dirp); } +#undef UCS2_ENDIAN #endif /* _WIN32 */ return r; } diff --git a/tests/Makefile.am b/tests/Makefile.am index 573e911a0b..2872cb1aa5 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -234,7 +234,7 @@ ctests += mini-record-2 simple gnutls_hmac_fast set_pkcs12_cred cert certuniquei set_x509_ocsp_multi_cli kdf-api keylog-func handshake-write \ x509cert-dntypes id-on-xmppAddr tls13-compat-mode ciphersuite-name \ x509-upnconstraint xts-key-check cipher-padding pkcs7-verify-double-free \ - fips-rsa-sizes tls12-rehandshake-ticket + fips-rsa-sizes tls12-rehandshake-ticket pathbuf ctests += tls-channel-binding @@ -480,6 +480,10 @@ buffer_CPPFLAGS = $(AM_CPPFLAGS) \ -I$(top_srcdir)/gl \ -I$(top_builddir)/gl +pathbuf_CPPFLAGS = $(AM_CPPFLAGS) \ + -I$(top_srcdir)/gl \ + -I$(top_builddir)/gl + if ENABLE_PKCS11 if !WINDOWS ctests += tls13/post-handshake-with-cert-pkcs11 pkcs11/tls-neg-pkcs11-no-key \ diff --git a/tests/pathbuf.c b/tests/pathbuf.c new file mode 100644 index 0000000000..f308ac090a --- /dev/null +++ b/tests/pathbuf.c @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2022 Red Hat, Inc. + * + * Author: Daiki Ueno + * + * This file is part of GnuTLS. + * + * The GnuTLS is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/> + * + */ + +#include <config.h> + +#include "../lib/pathbuf.h" +#include "utils.h" +#include <string.h> +#include <assert.h> + +static char long_path[GNUTLS_PATH_MAX + 2]; + +void +doit(void) +{ + struct gnutls_pathbuf_st pathbuf; + int i; + int ret; + + ret = _gnutls_pathbuf_init(&pathbuf, "./x509certs"); + assert(ret == 0); + assert(strcmp(pathbuf.ptr, "./x509certs") == 0); + assert(pathbuf.len == sizeof("./x509certs") - 1); + + ret = _gnutls_pathbuf_append(&pathbuf, "cert.pem"); + assert(ret == 0); + assert(strcmp(pathbuf.ptr, "./x509certs/cert.pem") == 0); + assert(pathbuf.len == sizeof("./x509certs/cert.pem") - 1); + _gnutls_pathbuf_deinit(&pathbuf); + + for (i = -1; i <= 1; i++) { + memset(long_path, 'a', GNUTLS_PATH_MAX + i); + long_path[GNUTLS_PATH_MAX + i] = '\0'; + + ret = _gnutls_pathbuf_init(&pathbuf, long_path); + assert(ret == 0); + assert(strcmp(pathbuf.ptr, long_path) == 0); + assert(pathbuf.len == (size_t)GNUTLS_PATH_MAX + i); + + ret = _gnutls_pathbuf_append(&pathbuf, "cert.pem"); + assert(ret == 0); + assert(memcmp(pathbuf.ptr, long_path, GNUTLS_PATH_MAX + i) == 0); + assert(strcmp(&pathbuf.ptr[GNUTLS_PATH_MAX + i], "/cert.pem") == 0); + assert(pathbuf.len == GNUTLS_PATH_MAX + i + sizeof("/cert.pem") - 1); + _gnutls_pathbuf_deinit(&pathbuf); + } +} |