Blame lib/system/certs.c

Packit Service 4684c1
/*
Packit Service 4684c1
 * Copyright (C) 2010-2016 Free Software Foundation, Inc.
Packit Service 4684c1
 * Copyright (C) 2015-2016 Red Hat, Inc.
Packit Service 4684c1
 *
Packit Service 4684c1
 * Author: Nikos Mavrogiannopoulos
Packit Service 4684c1
 *
Packit Service 4684c1
 * This file is part of GnuTLS.
Packit Service 4684c1
 *
Packit Service 4684c1
 * The GnuTLS is free software; you can redistribute it and/or
Packit Service 4684c1
 * modify it under the terms of the GNU Lesser General Public License
Packit Service 4684c1
 * as published by the Free Software Foundation; either version 2.1 of
Packit Service 4684c1
 * the License, or (at your option) any later version.
Packit Service 4684c1
 *
Packit Service 4684c1
 * This library is distributed in the hope that it will be useful, but
Packit Service 4684c1
 * WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 4684c1
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 4684c1
 * Lesser General Public License for more details.
Packit Service 4684c1
 *
Packit Service 4684c1
 * You should have received a copy of the GNU Lesser General Public License
Packit Service 4684c1
 * along with this program.  If not, see <https://www.gnu.org/licenses/>
Packit Service 4684c1
 *
Packit Service 4684c1
 */
Packit Service 4684c1
Packit Service 4684c1
#include <config.h>
Packit Service 4684c1
#include "gnutls_int.h"
Packit Service 4684c1
#include "errors.h"
Packit Service 4684c1
Packit Service 4684c1
#include <sys/socket.h>
Packit Service 4684c1
#include <errno.h>
Packit Service 4684c1
#include <sys/stat.h>
Packit Service 4684c1
#include <sys/types.h>
Packit Service 4684c1
#include "system.h"
Packit Service 4684c1
Packit Service 4684c1
#ifdef _WIN32
Packit Service 4684c1
# include <windows.h>
Packit Service 4684c1
# include <wincrypt.h>
Packit Service 4684c1
Packit Service 4684c1
#else /* !_WIN32 */
Packit Service 4684c1
Packit Service 4684c1
# include <poll.h>
Packit Service 4684c1
Packit Service 4684c1
# if defined(HAVE_GETPWUID_R)
Packit Service 4684c1
#  include <pwd.h>
Packit Service 4684c1
# endif
Packit Service 4684c1
#endif
Packit Service 4684c1
Packit Service 4684c1
#ifdef __APPLE__
Packit Service 4684c1
# include <CoreFoundation/CoreFoundation.h>
Packit Service 4684c1
# include <Security/Security.h>
Packit Service 4684c1
# include <Availability.h>
Packit Service 4684c1
#endif
Packit Service 4684c1
Packit Service 4684c1
/* System specific function wrappers for certificate stores.
Packit Service 4684c1
 */
Packit Service 4684c1
Packit Service 4684c1
#define CONFIG_PATH ".gnutls"
Packit Service 4684c1
Packit Service 4684c1
/* Returns a path to store user-specific configuration
Packit Service 4684c1
 * data.
Packit Service 4684c1
 */
Packit Service 4684c1
int _gnutls_find_config_path(char *path, size_t max_size)
Packit Service 4684c1
{
Packit Service 4684c1
	const char *home_dir = secure_getenv("HOME");
Packit Service 4684c1
Packit Service 4684c1
	if (home_dir != NULL && home_dir[0] != 0) {
Packit Service 4684c1
		snprintf(path, max_size, "%s/" CONFIG_PATH, home_dir);
Packit Service 4684c1
		return 0;
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
#ifdef _WIN32
Packit Service 4684c1
	if (home_dir == NULL || home_dir[0] == '\0') {
Packit Service 4684c1
		const char *home_drive = getenv("HOMEDRIVE");
Packit Service 4684c1
		const char *home_path = getenv("HOMEPATH");
Packit Service 4684c1
Packit Service 4684c1
		if (home_drive != NULL && home_path != NULL) {
Packit Service 4684c1
			snprintf(path, max_size, "%s%s\\" CONFIG_PATH, home_drive, home_path);
Packit Service 4684c1
		} else {
Packit Service 4684c1
			path[0] = 0;
Packit Service 4684c1
		}
Packit Service 4684c1
	}
Packit Service 4684c1
#elif defined(HAVE_GETPWUID_R)
Packit Service 4684c1
	if (home_dir == NULL || home_dir[0] == '\0') {
Packit Service 4684c1
		struct passwd *pwd;
Packit Service 4684c1
		struct passwd _pwd;
Packit Service 4684c1
		int ret;
Packit Service 4684c1
		char tmp[512];
Packit Service 4684c1
Packit Service 4684c1
		ret = getpwuid_r(getuid(), &_pwd, tmp, sizeof(tmp), &pwd);
Packit Service 4684c1
		if (ret == 0 && pwd != NULL) {
Packit Service 4684c1
			snprintf(path, max_size, "%s/" CONFIG_PATH, pwd->pw_dir);
Packit Service 4684c1
		} else {
Packit Service 4684c1
			path[0] = 0;
Packit Service 4684c1
		}
Packit Service 4684c1
	}
Packit Service 4684c1
#else
Packit Service 4684c1
	if (home_dir == NULL || home_dir[0] == '\0') {
Packit Service 4684c1
			path[0] = 0;
Packit Service 4684c1
	}
Packit Service 4684c1
#endif
Packit Service 4684c1
Packit Service 4684c1
	return 0;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
#if defined(DEFAULT_TRUST_STORE_FILE) || (defined(DEFAULT_TRUST_STORE_PKCS11) && defined(ENABLE_PKCS11))
Packit Service 4684c1
static
Packit Service 4684c1
int
Packit Service 4684c1
add_system_trust(gnutls_x509_trust_list_t list,
Packit Service 4684c1
		 unsigned int tl_flags, unsigned int tl_vflags)
Packit Service 4684c1
{
Packit Service 4684c1
	int ret, r = 0;
Packit Service 4684c1
	const char *crl_file =
Packit Service 4684c1
#ifdef DEFAULT_CRL_FILE
Packit Service 4684c1
	    DEFAULT_CRL_FILE;
Packit Service 4684c1
#else
Packit Service 4684c1
	    NULL;
Packit Service 4684c1
#endif
Packit Service 4684c1
Packit Service 4684c1
#if defined(ENABLE_PKCS11) && defined(DEFAULT_TRUST_STORE_PKCS11)
Packit Service 4684c1
	ret =
Packit Service 4684c1
	    gnutls_x509_trust_list_add_trust_file(list,
Packit Service 4684c1
						  DEFAULT_TRUST_STORE_PKCS11,
Packit Service 4684c1
						  crl_file,
Packit Service 4684c1
						  GNUTLS_X509_FMT_DER,
Packit Service 4684c1
						  tl_flags, tl_vflags);
Packit Service 4684c1
	if (ret > 0)
Packit Service 4684c1
		r += ret;
Packit Service 4684c1
#endif
Packit Service 4684c1
Packit Service 4684c1
#ifdef DEFAULT_TRUST_STORE_FILE
Packit Service 4684c1
	ret =
Packit Service 4684c1
	    gnutls_x509_trust_list_add_trust_file(list,
Packit Service 4684c1
						  DEFAULT_TRUST_STORE_FILE,
Packit Service 4684c1
						  crl_file,
Packit Service 4684c1
						  GNUTLS_X509_FMT_PEM,
Packit Service 4684c1
						  tl_flags, tl_vflags);
Packit Service 4684c1
	if (ret > 0)
Packit Service 4684c1
		r += ret;
Packit Service 4684c1
#endif
Packit Service 4684c1
Packit Service 4684c1
#ifdef DEFAULT_BLACKLIST_FILE
Packit Service 4684c1
	ret = gnutls_x509_trust_list_remove_trust_file(list, DEFAULT_BLACKLIST_FILE, GNUTLS_X509_FMT_PEM);
Packit Service 4684c1
	if (ret < 0) {
Packit Service 4684c1
		_gnutls_debug_log("Could not load blacklist file '%s'\n", DEFAULT_BLACKLIST_FILE);
Packit Service 4684c1
	}
Packit Service 4684c1
#endif
Packit Service 4684c1
Packit Service 4684c1
	return r;
Packit Service 4684c1
}
Packit Service 4684c1
#elif defined(_WIN32)
Packit Service 4684c1
static
Packit Service 4684c1
int add_system_trust(gnutls_x509_trust_list_t list, unsigned int tl_flags,
Packit Service 4684c1
		     unsigned int tl_vflags)
Packit Service 4684c1
{
Packit Service 4684c1
	unsigned int i;
Packit Service 4684c1
	int r = 0;
Packit Service 4684c1
Packit Service 4684c1
	for (i = 0; i < 2; i++) {
Packit Service 4684c1
		HCERTSTORE store;
Packit Service 4684c1
		const CERT_CONTEXT *cert;
Packit Service 4684c1
		const CRL_CONTEXT *crl;
Packit Service 4684c1
		gnutls_datum_t data;
Packit Service 4684c1
Packit Service 4684c1
		if (i == 0)
Packit Service 4684c1
			store = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0, CERT_SYSTEM_STORE_CURRENT_USER , L"ROOT");
Packit Service 4684c1
		else
Packit Service 4684c1
			store = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0, CERT_SYSTEM_STORE_CURRENT_USER, L"CA");
Packit Service 4684c1
Packit Service 4684c1
		if (store == NULL)
Packit Service 4684c1
			return GNUTLS_E_FILE_ERROR;
Packit Service 4684c1
Packit Service 4684c1
		cert = CertEnumCertificatesInStore(store, NULL);
Packit Service 4684c1
		crl = pCertEnumCRLsInStore(store, NULL);
Packit Service 4684c1
Packit Service 4684c1
		while (cert != NULL) {
Packit Service 4684c1
			if (cert->dwCertEncodingType == X509_ASN_ENCODING) {
Packit Service 4684c1
				data.data = cert->pbCertEncoded;
Packit Service 4684c1
				data.size = cert->cbCertEncoded;
Packit Service 4684c1
				if (gnutls_x509_trust_list_add_trust_mem
Packit Service 4684c1
				    (list, &data, NULL,
Packit Service 4684c1
				     GNUTLS_X509_FMT_DER, tl_flags,
Packit Service 4684c1
				     tl_vflags) > 0)
Packit Service 4684c1
					r++;
Packit Service 4684c1
			}
Packit Service 4684c1
			cert = CertEnumCertificatesInStore(store, cert);
Packit Service 4684c1
		}
Packit Service 4684c1
Packit Service 4684c1
		while (crl != NULL) {
Packit Service 4684c1
			if (crl->dwCertEncodingType == X509_ASN_ENCODING) {
Packit Service 4684c1
				data.data = crl->pbCrlEncoded;
Packit Service 4684c1
				data.size = crl->cbCrlEncoded;
Packit Service 4684c1
				gnutls_x509_trust_list_add_trust_mem(list,
Packit Service 4684c1
								     NULL,
Packit Service 4684c1
								     &data,
Packit Service 4684c1
								     GNUTLS_X509_FMT_DER,
Packit Service 4684c1
								     tl_flags,
Packit Service 4684c1
								     tl_vflags);
Packit Service 4684c1
			}
Packit Service 4684c1
			crl = pCertEnumCRLsInStore(store, crl);
Packit Service 4684c1
		}
Packit Service 4684c1
		CertCloseStore(store, 0);
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
#ifdef DEFAULT_BLACKLIST_FILE
Packit Service 4684c1
	ret = gnutls_x509_trust_list_remove_trust_file(list, DEFAULT_BLACKLIST_FILE, GNUTLS_X509_FMT_PEM);
Packit Service 4684c1
	if (ret < 0) {
Packit Service 4684c1
		_gnutls_debug_log("Could not load blacklist file '%s'\n", DEFAULT_BLACKLIST_FILE);
Packit Service 4684c1
	}
Packit Service 4684c1
#endif
Packit Service 4684c1
Packit Service 4684c1
	return r;
Packit Service 4684c1
}
Packit Service 4684c1
#elif defined(ANDROID) || defined(__ANDROID__) || defined(DEFAULT_TRUST_STORE_DIR)
Packit Service 4684c1
Packit Service 4684c1
# include <dirent.h>
Packit Service 4684c1
# include <unistd.h>
Packit Service 4684c1
Packit Service 4684c1
# if defined(ANDROID) || defined(__ANDROID__)
Packit Service 4684c1
#  define DEFAULT_TRUST_STORE_DIR "/system/etc/security/cacerts/"
Packit Service 4684c1
Packit Service 4684c1
static int load_revoked_certs(gnutls_x509_trust_list_t list, unsigned type)
Packit Service 4684c1
{
Packit Service 4684c1
	DIR *dirp;
Packit Service 4684c1
	struct dirent *d;
Packit Service 4684c1
	int ret;
Packit Service 4684c1
	int r = 0;
Packit Service 4684c1
	char path[GNUTLS_PATH_MAX];
Packit Service 4684c1
Packit Service 4684c1
	dirp = opendir("/data/misc/keychain/cacerts-removed/");
Packit Service 4684c1
	if (dirp != NULL) {
Packit Service 4684c1
		do {
Packit Service 4684c1
			d = readdir(dirp);
Packit Service 4684c1
			if (d != NULL && d->d_type == DT_REG) {
Packit Service 4684c1
				snprintf(path, sizeof(path),
Packit Service 4684c1
					 "/data/misc/keychain/cacerts-removed/%s",
Packit Service 4684c1
					 d->d_name);
Packit Service 4684c1
Packit Service 4684c1
				ret =
Packit Service 4684c1
				    gnutls_x509_trust_list_remove_trust_file
Packit Service 4684c1
				    (list, path, type);
Packit Service 4684c1
				if (ret >= 0)
Packit Service 4684c1
					r += ret;
Packit Service 4684c1
			}
Packit Service 4684c1
		}
Packit Service 4684c1
		while (d != NULL);
Packit Service 4684c1
		closedir(dirp);
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	return r;
Packit Service 4684c1
}
Packit Service 4684c1
# endif
Packit Service 4684c1
Packit Service 4684c1
Packit Service 4684c1
/* This works on android 4.x 
Packit Service 4684c1
 */
Packit Service 4684c1
static
Packit Service 4684c1
int add_system_trust(gnutls_x509_trust_list_t list, unsigned int tl_flags,
Packit Service 4684c1
		     unsigned int tl_vflags)
Packit Service 4684c1
{
Packit Service 4684c1
	int r = 0, ret;
Packit Service 4684c1
Packit Service 4684c1
	ret = gnutls_x509_trust_list_add_trust_dir(list, DEFAULT_TRUST_STORE_DIR,
Packit Service 4684c1
		NULL, GNUTLS_X509_FMT_PEM, tl_flags, tl_vflags);
Packit Service 4684c1
	if (ret >= 0)
Packit Service 4684c1
		r += ret;
Packit Service 4684c1
Packit Service 4684c1
# if defined(ANDROID) || defined(__ANDROID__)
Packit Service 4684c1
	ret = load_revoked_certs(list, GNUTLS_X509_FMT_DER);
Packit Service 4684c1
	if (ret >= 0)
Packit Service 4684c1
		r -= ret;
Packit Service 4684c1
Packit Service 4684c1
	ret = gnutls_x509_trust_list_add_trust_dir(list, "/data/misc/keychain/cacerts-added/",
Packit Service 4684c1
		NULL, GNUTLS_X509_FMT_DER, tl_flags, tl_vflags);
Packit Service 4684c1
	if (ret >= 0)
Packit Service 4684c1
		r += ret;
Packit Service 4684c1
# endif
Packit Service 4684c1
Packit Service 4684c1
	return r;
Packit Service 4684c1
}
Packit Service 4684c1
#elif defined(__APPLE__) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
Packit Service 4684c1
static
Packit Service 4684c1
int osstatus_error(status)
Packit Service 4684c1
{
Packit Service 4684c1
	CFStringRef err_str = SecCopyErrorMessageString(status, NULL);
Packit Service 4684c1
	_gnutls_debug_log("Error loading system root certificates: %s\n",
Packit Service 4684c1
			  CFStringGetCStringPtr(err_str, kCFStringEncodingUTF8));
Packit Service 4684c1
	CFRelease(err_str);
Packit Service 4684c1
	return GNUTLS_E_FILE_ERROR;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
static
Packit Service 4684c1
int add_system_trust(gnutls_x509_trust_list_t list, unsigned int tl_flags,
Packit Service 4684c1
		     unsigned int tl_vflags)
Packit Service 4684c1
{
Packit Service 4684c1
	int r=0;
Packit Service 4684c1
Packit Service 4684c1
	SecTrustSettingsDomain domain[] = { kSecTrustSettingsDomainUser,
Packit Service 4684c1
					    kSecTrustSettingsDomainAdmin,
Packit Service 4684c1
					    kSecTrustSettingsDomainSystem };
Packit Service 4684c1
	for (size_t d=0; d
Packit Service 4684c1
		CFArrayRef certs = NULL;
Packit Service 4684c1
		OSStatus status = SecTrustSettingsCopyCertificates(domain[d],
Packit Service 4684c1
								   &certs);
Packit Service 4684c1
		if (status == errSecNoTrustSettings)
Packit Service 4684c1
			continue;
Packit Service 4684c1
		if (status != errSecSuccess)
Packit Service 4684c1
			return osstatus_error(status);
Packit Service 4684c1
Packit Service 4684c1
		int cert_count = CFArrayGetCount(certs);
Packit Service 4684c1
		for (int i=0; i
Packit Service 4684c1
			SecCertificateRef cert =
Packit Service 4684c1
				(void*)CFArrayGetValueAtIndex(certs, i);
Packit Service 4684c1
			CFDataRef der;
Packit Service 4684c1
			status = SecItemExport(cert, kSecFormatX509Cert, 0,
Packit Service 4684c1
					       NULL, &der;;
Packit Service 4684c1
			if (status != errSecSuccess) {
Packit Service 4684c1
				CFRelease(der);
Packit Service 4684c1
				CFRelease(certs);
Packit Service 4684c1
				return osstatus_error(status);
Packit Service 4684c1
			}
Packit Service 4684c1
Packit Service 4684c1
			if (gnutls_x509_trust_list_add_trust_mem(list,
Packit Service 4684c1
								 &(gnutls_datum_t) {
Packit Service 4684c1
									.data = (void*)CFDataGetBytePtr(der),
Packit Service 4684c1
									.size = CFDataGetLength(der),
Packit Service 4684c1
								 },
Packit Service 4684c1
								 NULL,
Packit Service 4684c1
			                                         GNUTLS_X509_FMT_DER,
Packit Service 4684c1
								 tl_flags,
Packit Service 4684c1
								 tl_vflags) > 0)
Packit Service 4684c1
				r++;
Packit Service 4684c1
			CFRelease(der);
Packit Service 4684c1
		}
Packit Service 4684c1
		CFRelease(certs);
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
#ifdef DEFAULT_BLACKLIST_FILE
Packit Service 4684c1
	ret = gnutls_x509_trust_list_remove_trust_file(list, DEFAULT_BLACKLIST_FILE, GNUTLS_X509_FMT_PEM);
Packit Service 4684c1
	if (ret < 0) {
Packit Service 4684c1
		_gnutls_debug_log("Could not load blacklist file '%s'\n", DEFAULT_BLACKLIST_FILE);
Packit Service 4684c1
	}
Packit Service 4684c1
#endif
Packit Service 4684c1
Packit Service 4684c1
	return r;
Packit Service 4684c1
}
Packit Service 4684c1
#else
Packit Service 4684c1
Packit Service 4684c1
#define add_system_trust(x,y,z) GNUTLS_E_UNIMPLEMENTED_FEATURE
Packit Service 4684c1
Packit Service 4684c1
#endif
Packit Service 4684c1
Packit Service 4684c1
/**
Packit Service 4684c1
 * gnutls_x509_trust_list_add_system_trust:
Packit Service 4684c1
 * @list: The structure of the list
Packit Service 4684c1
 * @tl_flags: GNUTLS_TL_*
Packit Service 4684c1
 * @tl_vflags: gnutls_certificate_verify_flags if flags specifies GNUTLS_TL_VERIFY_CRL
Packit Service 4684c1
 *
Packit Service 4684c1
 * This function adds the system's default trusted certificate
Packit Service 4684c1
 * authorities to the trusted list. Note that on unsupported systems
Packit Service 4684c1
 * this function returns %GNUTLS_E_UNIMPLEMENTED_FEATURE.
Packit Service 4684c1
 *
Packit Service 4684c1
 * This function implies the flag %GNUTLS_TL_NO_DUPLICATES.
Packit Service 4684c1
 *
Packit Service 4684c1
 * Returns: The number of added elements or a negative error code on error.
Packit Service 4684c1
 *
Packit Service 4684c1
 * Since: 3.1
Packit Service 4684c1
 **/
Packit Service 4684c1
int
Packit Service 4684c1
gnutls_x509_trust_list_add_system_trust(gnutls_x509_trust_list_t list,
Packit Service 4684c1
					unsigned int tl_flags,
Packit Service 4684c1
					unsigned int tl_vflags)
Packit Service 4684c1
{
Packit Service 4684c1
	return add_system_trust(list, tl_flags|GNUTLS_TL_NO_DUPLICATES, tl_vflags);
Packit Service 4684c1
}
Packit Service 4684c1