resolve,import: always use openssl (#36937)

This commit is contained in:
Daan De Meyer
2025-04-18 15:30:33 +02:00
committed by GitHub
30 changed files with 122 additions and 969 deletions

View File

@@ -10,7 +10,7 @@ fatal() { echo >&2 -e "\033[31;1m$1\033[0m"; exit 1; }
success() { echo >&2 -e "\033[32;1m$1\033[0m"; }
ARGS=(
"--optimization=0 -Dopenssl=disabled -Dcryptolib=gcrypt -Ddns-over-tls=gnutls -Dtpm=true -Dtpm2=enabled"
"--optimization=0 -Dopenssl=disabled -Dtpm=true -Dtpm2=enabled"
"--optimization=s -Dutmp=false"
"--optimization=2 -Dc_args=-Wmaybe-uninitialized -Ddns-over-tls=openssl"
"--optimization=3 -Db_lto=true -Ddns-over-tls=false"
@@ -67,7 +67,6 @@ PACKAGES=(
COMPILER="${COMPILER:?}"
COMPILER_VERSION="${COMPILER_VERSION:?}"
LINKER="${LINKER:?}"
CRYPTOLIB="${CRYPTOLIB:?}"
RELEASE="$(lsb_release -cs)"
# Note: As we use postfixed clang/gcc binaries, we need to override $AR
@@ -150,7 +149,7 @@ for args in "${ARGS[@]}"; do
CXX="$CXX" CXX_LD="$LINKER" CXXFLAGS="$CXXFLAGS" \
meson setup \
-Dtests=unsafe -Dslow-tests=true -Dfuzz-tests=true --werror \
-Dnobody-group=nogroup -Dcryptolib="${CRYPTOLIB:?}" -Ddebug=false \
-Dnobody-group=nogroup -Ddebug=false \
$args build; then
cat build/meson-logs/meson-log.txt

View File

@@ -25,11 +25,11 @@ jobs:
fail-fast: false
matrix:
env:
- { COMPILER: "gcc", COMPILER_VERSION: "11", LINKER: "bfd", CRYPTOLIB: "gcrypt" }
- { COMPILER: "gcc", COMPILER_VERSION: "13", LINKER: "mold", CRYPTOLIB: "openssl" }
- { COMPILER: "clang", COMPILER_VERSION: "14", LINKER: "mold", CRYPTOLIB: "gcrypt" }
- { COMPILER: "clang", COMPILER_VERSION: "16", LINKER: "bfd", CRYPTOLIB: "openssl" }
- { COMPILER: "clang", COMPILER_VERSION: "18", LINKER: "lld", CRYPTOLIB: "auto" }
- { COMPILER: "gcc", COMPILER_VERSION: "11", LINKER: "bfd" }
- { COMPILER: "gcc", COMPILER_VERSION: "13", LINKER: "mold" }
- { COMPILER: "clang", COMPILER_VERSION: "14", LINKER: "mold" }
- { COMPILER: "clang", COMPILER_VERSION: "16", LINKER: "bfd" }
- { COMPILER: "clang", COMPILER_VERSION: "18", LINKER: "lld" }
env: ${{ matrix.env }}
steps:
- name: Repository checkout

View File

@@ -41,7 +41,7 @@ function run_meson() {
set -ex
MESON_ARGS=(-Dcryptolib=${CRYPTOLIB:-auto})
MESON_ARGS=()
# (Re)set the current oom-{score-}adj. For some reason root on GH actions is able to _decrease_
# its oom-score even after dropping all capabilities (including CAP_SYS_RESOURCE), until the

View File

@@ -16,18 +16,15 @@ jobs:
build:
runs-on: ubuntu-24.04
concurrency:
group: ${{ github.workflow }}-${{ matrix.run_phase }}-${{ matrix.cryptolib }}-${{ github.ref }}
group: ${{ github.workflow }}-${{ matrix.run_phase }}-${{ github.ref }}
cancel-in-progress: true
strategy:
fail-fast: false
matrix:
run_phase: [GCC, GCC_ASAN_UBSAN, CLANG, CLANG_RELEASE, CLANG_ASAN_UBSAN, CLANG_ASAN_UBSAN_NO_DEPS]
cryptolib: [auto]
include:
- run_phase: GCC
cryptolib: openssl
- run_phase: CLANG
cryptolib: gcrypt
steps:
- name: Repository checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
@@ -38,8 +35,6 @@ jobs:
sudo sed -i '/^XDG_/d' /etc/environment
# Pass only specific env variables through sudo, to avoid having
# the already existing XDG_* stuff on the "other side"
sudo --preserve-env=CRYPTOLIB,GITHUB_ACTIONS,CI .github/workflows/unit_tests.sh SETUP
sudo --preserve-env=GITHUB_ACTIONS,CI .github/workflows/unit_tests.sh SETUP
- name: Build & test
run: sudo --preserve-env=CRYPTOLIB,GITHUB_ACTIONS,CI .github/workflows/unit_tests.sh RUN_${{ matrix.run_phase }}
env:
CRYPTOLIB: ${{ matrix.cryptolib }}
run: sudo --preserve-env=GITHUB_ACTIONS,CI .github/workflows/unit_tests.sh RUN_${{ matrix.run_phase }}

6
NEWS
View File

@@ -67,6 +67,12 @@ CHANGES WITH 258 in spe:
in v255), 'default-hierarchy' (v256), and 'nscd' (v257) have been
removed.
* OpenSSL is the only crypto backend for systemd-resolved and
systemd-importd, and support for gnutls and gcrypt has been removed.
Hence, support for 'dns-over-tls=gnutls' meson option has been
removed. Also, 'cryptolib' meson option has been deprecated, and will
be removed in a future release.
Announcements of Future Feature Removals:
* The D-Bus method org.freedesktop.systemd1.StartAuxiliaryScope() is

3
README
View File

@@ -240,8 +240,7 @@ REQUIREMENTS:
libcurl >= 7.32.0 (optional)
libidn2 or libidn (optional)
gnutls >= 3.1.4 (optional)
>= 3.6.0 is required to support DNS-over-TLS with gnutls
openssl >= 1.1.0 (optional, required to support DNS-over-TLS with openssl)
openssl >= 1.1.0 (optional, required to support DNS-over-TLS)
p11-kit >= 0.23.3 (optional)
libfido2 (optional)
tpm2-tss (optional)

1
TODO
View File

@@ -1791,7 +1791,6 @@ Features:
with matches, then activate app through that passing socket over
* unify on openssl:
- kill gnutls support in resolved
- figure out what to do about libmicrohttpd, which has a hard dependency on
gnutls
- port fsprg over to a dlopen lib, then switch it to openssl

View File

@@ -1482,50 +1482,18 @@ endif
dmi_arches = ['x86', 'x86_64', 'aarch64', 'arm', 'ia64', 'loongarch64', 'mips', 'riscv64']
conf.set10('HAVE_DMI', host_machine.cpu_family() in dmi_arches)
# We support one or the other. If gcrypt is available, we assume it's there to
# be used, and use it in preference.
opt = get_option('cryptolib')
if opt == 'openssl' and conf.get('HAVE_OPENSSL') == 0
error('openssl requested as the default cryptolib, but not available')
endif
conf.set10('PREFER_OPENSSL',
opt == 'openssl' or (opt == 'auto' and conf.get('HAVE_OPENSSL') == 1 and conf.get('HAVE_GCRYPT') == 0))
conf.set10('HAVE_OPENSSL_OR_GCRYPT',
conf.get('HAVE_OPENSSL') == 1 or conf.get('HAVE_GCRYPT') == 1)
lib_openssl_or_gcrypt = conf.get('PREFER_OPENSSL') == 1 ? [libopenssl] : [libgcrypt, libgpg_error]
dns_over_tls = get_option('dns-over-tls')
if dns_over_tls != 'false'
if dns_over_tls == 'gnutls' and conf.get('PREFER_OPENSSL') == 1
error('Sorry, -Ddns-over-tls=gnutls is not supported when openssl is used as the cryptolib')
endif
if dns_over_tls == 'gnutls'
have_openssl = false
else
have_openssl = conf.get('HAVE_OPENSSL') == 1
if dns_over_tls == 'openssl' and not have_openssl
error('DNS-over-TLS support was requested with openssl, but dependencies are not available')
endif
endif
if dns_over_tls == 'openssl' or have_openssl
have_gnutls = false
else
have_gnutls = conf.get('HAVE_GNUTLS') == 1 and libgnutls.version().version_compare('>= 3.6.0')
if dns_over_tls != 'auto' and not have_gnutls
str = dns_over_tls == 'gnutls' ? ' with gnutls' : ''
error('DNS-over-TLS support was requested@0@, but dependencies are not available'.format(str))
endif
endif
have = have_gnutls or have_openssl
else
have_openssl = conf.get('HAVE_OPENSSL') == 1
if dns_over_tls == 'false'
have = false
have_gnutls = false
have_openssl = false
elif dns_over_tls == 'auto'
have = have_openssl
elif have_openssl
have = true
else
error('DNS-over-TLS support was requested, but OpenSSL support is disabled.')
endif
conf.set10('ENABLE_DNS_OVER_TLS', have)
conf.set10('DNS_OVER_TLS_USE_GNUTLS', have_gnutls)
conf.set10('DNS_OVER_TLS_USE_OPENSSL', have_openssl)
default_dns_over_tls = get_option('default-dns-over-tls')
if default_dns_over_tls != 'no' and conf.get('ENABLE_DNS_OVER_TLS') == 0
@@ -1552,8 +1520,8 @@ have = get_option('repart').require(
conf.set10('ENABLE_REPART', have)
default_dnssec = get_option('default-dnssec')
if default_dnssec != 'no' and conf.get('HAVE_OPENSSL_OR_GCRYPT') == 0
message('default-dnssec cannot be set to yes or allow-downgrade openssl and gcrypt are disabled. Setting default-dnssec to no.')
if default_dnssec != 'no' and conf.get('HAVE_OPENSSL') == 0
message('default-dnssec cannot be set to yes or allow-downgrade when openssl is disabled. Setting default-dnssec to no.')
default_dnssec = 'no'
endif
conf.set('DEFAULT_DNSSEC_MODE',
@@ -1584,7 +1552,7 @@ conf.set10('ENABLE_STORAGETM', get_option('storagetm'))
have = get_option('importd').require(
conf.get('HAVE_LIBCURL') == 1 and
conf.get('HAVE_OPENSSL_OR_GCRYPT') == 1 and
conf.get('HAVE_OPENSSL') == 1 and
conf.get('HAVE_ZLIB') == 1 and
conf.get('HAVE_XZ') == 1,
error_message : 'curl, openssl/grypt, zlib and xz required').allowed()
@@ -3097,6 +3065,7 @@ foreach tuple : [
# optional features
['dmi'],
['DNS-over-TLS'],
['idn'],
['polkit'],
['legacy-pkla', install_polkit_pkla],
@@ -3161,22 +3130,6 @@ else
found += 'static-libudev(@0@)'.format(static_libudev)
endif
if conf.get('HAVE_OPENSSL_OR_GCRYPT') == 1 and conf.get('PREFER_OPENSSL') == 1
found += 'cryptolib(openssl)'
elif conf.get('HAVE_OPENSSL_OR_GCRYPT') == 1
found += 'cryptolib(gcrypt)'
else
missing += 'cryptolib'
endif
if conf.get('DNS_OVER_TLS_USE_GNUTLS') == 1
found += 'DNS-over-TLS(gnutls)'
elif conf.get('DNS_OVER_TLS_USE_OPENSSL') == 1
found += 'DNS-over-TLS(openssl)'
else
missing += 'DNS-over-TLS'
endif
summary({
'enabled' : ', '.join(found),
'disabled' : ', '.join(missing)},

View File

@@ -358,7 +358,7 @@ option('default-llmnr', type : 'combo',
choices : ['yes', 'resolve', 'no'],
description : 'default LLMNR mode',
value : 'yes')
option('dns-over-tls', type : 'combo', choices : ['auto', 'gnutls', 'openssl', 'true', 'false'],
option('dns-over-tls', type : 'combo', choices : ['auto', 'openssl', 'true', 'false'],
description : 'DNS-over-TLS support')
option('dns-servers', type : 'string',
description : 'space-separated list of default DNS servers',
@@ -434,8 +434,8 @@ option('gnutls', type : 'feature', deprecated : { 'true' : 'enabled', 'false' :
description : 'gnutls support')
option('openssl', type : 'feature', deprecated : { 'true' : 'enabled', 'false' : 'disabled' },
description : 'openssl support')
option('cryptolib', type : 'combo', choices : ['auto', 'openssl', 'gcrypt'],
description : 'whether to use openssl or gcrypt where both are supported')
option('cryptolib', type : 'combo', choices : ['auto', 'openssl'],
description : 'This option is deprecated and will be removed in a future release')
option('p11kit', type : 'feature', deprecated : { 'true' : 'enabled', 'false' : 'disabled' },
description : 'p11kit support')
option('libfido2', type : 'feature', deprecated : { 'true' : 'enabled', 'false' : 'disabled' },

View File

@@ -106,39 +106,4 @@ int initialize_libgcrypt(bool secmem) {
return 0;
}
# if !PREFER_OPENSSL
int string_hashsum(const char *s, size_t len, int md_algorithm, char **out) {
_cleanup_(sym_gcry_md_closep) gcry_md_hd_t md = NULL;
gcry_error_t err;
size_t hash_size;
void *hash;
char *enc;
int r;
r = initialize_libgcrypt(false);
if (r < 0)
return r;
hash_size = sym_gcry_md_get_algo_dlen(md_algorithm);
assert(hash_size > 0);
err = sym_gcry_md_open(&md, md_algorithm, 0);
if (gcry_err_code(err) != GPG_ERR_NO_ERROR || !md)
return -EIO;
sym_gcry_md_write(md, s, len);
hash = sym_gcry_md_read(md, 0);
if (!hash)
return -EIO;
enc = hexmem(hash, hash_size);
if (!enc)
return -ENOMEM;
*out = enc;
return 0;
}
# endif
#endif

View File

@@ -64,25 +64,3 @@ DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(gcry_md_hd_t, gcry_md_close, NULL);
(h__)->buf[(h__)->bufpos++] = (c) & 0xff; \
} while(false)
#endif
#if !PREFER_OPENSSL
# if HAVE_GCRYPT
int string_hashsum(const char *s, size_t len, int md_algorithm, char **out);
# endif
static inline int string_hashsum_sha224(const char *s, size_t len, char **out) {
# if HAVE_GCRYPT
return string_hashsum(s, len, GCRY_MD_SHA224, out);
# else
return -EOPNOTSUPP;
# endif
}
static inline int string_hashsum_sha256(const char *s, size_t len, char **out) {
# if HAVE_GCRYPT
return string_hashsum(s, len, GCRY_MD_SHA256, out);
# else
return -EOPNOTSUPP;
# endif
}
#endif

View File

@@ -80,7 +80,7 @@ executables += [
'sources' : systemd_pull_sources,
'link_with' : common_libs,
'dependencies' : common_deps + [
lib_openssl_or_gcrypt,
libopenssl,
],
},
libexec_template + {

View File

@@ -7,7 +7,6 @@
#include "alloc-util.h"
#include "fd-util.h"
#include "format-util.h"
#include "gcrypt-util.h"
#include "hexdecoct.h"
#include "import-util.h"
#include "io-util.h"
@@ -43,11 +42,7 @@ PullJob* pull_job_unref(PullJob *j) {
import_compress_free(&j->compress);
if (j->checksum_ctx)
#if PREFER_OPENSSL
EVP_MD_CTX_free(j->checksum_ctx);
#else
gcry_md_close(j->checksum_ctx);
#endif
free(j->url);
free(j->etag);
@@ -108,11 +103,7 @@ static int pull_job_restart(PullJob *j, const char *new_url) {
import_compress_free(&j->compress);
if (j->checksum_ctx) {
#if PREFER_OPENSSL
EVP_MD_CTX_free(j->checksum_ctx);
#else
gcry_md_close(j->checksum_ctx);
#endif
j->checksum_ctx = NULL;
}
@@ -211,7 +202,6 @@ void pull_job_curl_on_finished(CurlGlue *g, CURL *curl, CURLcode result) {
if (j->checksum_ctx) {
unsigned checksum_len;
#if PREFER_OPENSSL
uint8_t k[EVP_MAX_MD_SIZE];
r = EVP_DigestFinal_ex(j->checksum_ctx, k, &checksum_len);
@@ -220,17 +210,6 @@ void pull_job_curl_on_finished(CurlGlue *g, CURL *curl, CURLcode result) {
goto finish;
}
assert(checksum_len <= sizeof k);
#else
const uint8_t *k;
k = gcry_md_read(j->checksum_ctx, GCRY_MD_SHA256);
if (!k) {
r = log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to get checksum.");
goto finish;
}
checksum_len = gcry_md_get_algo_dlen(GCRY_MD_SHA256);
#endif
j->checksum = hexmem(k, checksum_len);
if (!j->checksum) {
@@ -381,14 +360,10 @@ static int pull_job_write_compressed(PullJob *j, void *p, size_t sz) {
"Content length incorrect.");
if (j->checksum_ctx) {
#if PREFER_OPENSSL
r = EVP_DigestUpdate(j->checksum_ctx, p, sz);
if (r == 0)
return log_error_errno(SYNTHETIC_ERRNO(EIO),
"Could not hash chunk.");
#else
gcry_md_write(j->checksum_ctx, p, sz);
#endif
}
r = import_uncompress(&j->compress, p, sz, pull_job_write_uncompressed, j);
@@ -422,7 +397,6 @@ static int pull_job_open_disk(PullJob *j) {
}
if (j->calc_checksum) {
#if PREFER_OPENSSL
j->checksum_ctx = EVP_MD_CTX_new();
if (!j->checksum_ctx)
return log_oom();
@@ -431,15 +405,6 @@ static int pull_job_open_disk(PullJob *j) {
if (r == 0)
return log_error_errno(SYNTHETIC_ERRNO(EIO),
"Failed to initialize hash context.");
#else
r = initialize_libgcrypt(false);
if (r < 0)
return log_error_errno(r, "Failed to load libgcrypt: %m");
if (gcry_md_open(&j->checksum_ctx, GCRY_MD_SHA256, 0) != 0)
return log_error_errno(SYNTHETIC_ERRNO(EIO),
"Failed to initialize hash context.");
#endif
}
return 0;

View File

@@ -74,7 +74,7 @@ struct PullJob {
usec_t last_status_usec;
bool calc_checksum;
hash_context_t checksum_ctx;
EVP_MD_CTX *checksum_ctx;
char *checksum;
bool sync;

View File

@@ -100,21 +100,11 @@ systemd_resolved_sources += custom_target(
output : 'resolved-dnssd-gperf.c',
command : [gperf, '@INPUT@', '--output-file', '@OUTPUT@'])
systemd_resolved_dependencies = [threads, libm] + [lib_openssl_or_gcrypt]
systemd_resolved_dependencies = [threads, libm, libopenssl]
if conf.get('ENABLE_DNS_OVER_TLS') == 1
if conf.get('DNS_OVER_TLS_USE_GNUTLS') == 1
systemd_resolved_sources += files(
'resolved-dnstls-gnutls.c',
)
systemd_resolved_dependencies += libgnutls
elif conf.get('DNS_OVER_TLS_USE_OPENSSL') == 1
systemd_resolved_sources += files(
'resolved-dnstls-openssl.c',
)
systemd_resolved_dependencies += libopenssl
else
error('unknown dependency for supporting DNS-over-TLS')
endif
systemd_resolved_sources += files(
'resolved-dnstls.c',
)
endif
link_with = [
@@ -128,7 +118,7 @@ resolve_common_template = {
libsystemd_resolve_core,
],
'dependencies' : [
lib_openssl_or_gcrypt,
libopenssl,
libm,
],
}
@@ -153,7 +143,7 @@ executables += [
'sources' : resolvectl_sources,
'link_with' : link_with,
'dependencies' : [
lib_openssl_or_gcrypt,
libopenssl,
libidn,
libm,
threads,
@@ -197,7 +187,7 @@ executables += [
},
resolve_test_template + {
'sources' : files('test-dnssec.c'),
'conditions' : ['HAVE_OPENSSL_OR_GCRYPT'],
'conditions' : ['HAVE_OPENSSL'],
},
resolve_test_template + {
'sources' : files('test-dnssec-complex.c'),
@@ -209,11 +199,7 @@ executables += [
basic_dns_sources,
systemd_resolved_sources,
],
'dependencies' : [
lib_openssl_or_gcrypt,
libm,
systemd_resolved_dependencies,
],
'dependencies' : systemd_resolved_dependencies,
'include_directories' : resolve_includes,
},
test_template + {
@@ -266,11 +252,7 @@ executables += [
basic_dns_sources,
systemd_resolved_sources,
],
'dependencies' : [
lib_openssl_or_gcrypt,
libm,
systemd_resolved_dependencies,
],
'dependencies' : systemd_resolved_dependencies,
'include_directories' : resolve_includes,
},
test_template + {
@@ -279,11 +261,7 @@ executables += [
basic_dns_sources,
systemd_resolved_sources,
],
'dependencies' : [
lib_openssl_or_gcrypt,
libm,
systemd_resolved_dependencies,
],
'dependencies' : systemd_resolved_dependencies,
'include_directories' : resolve_includes,
'type' : 'manual',
},

View File

@@ -22,7 +22,6 @@
#include "escape.h"
#include "format-ifname.h"
#include "format-table.h"
#include "gcrypt-util.h"
#include "hostname-util.h"
#include "json-util.h"
#include "main-func.h"

View File

@@ -398,9 +398,9 @@ int manager_parse_config_file(Manager *m) {
return r;
}
#if !HAVE_OPENSSL_OR_GCRYPT
#if !HAVE_OPENSSL
if (m->dnssec_mode != DNSSEC_NO) {
log_warning("DNSSEC option cannot be enabled or set to allow-downgrade when systemd-resolved is built without a cryptographic library. Turning off DNSSEC support.");
log_warning("DNSSEC option cannot be enabled or set to allow-downgrade when systemd-resolved is built without openssl. Turning off DNSSEC support.");
m->dnssec_mode = DNSSEC_NO;
}
#endif

View File

@@ -4,7 +4,6 @@
#include "dns-domain.h"
#include "fd-util.h"
#include "fileio.h"
#include "gcrypt-util.h"
#include "hexdecoct.h"
#include "log.h"
#include "memory-util.h"
@@ -15,7 +14,7 @@
#include "sort-util.h"
#include "string-table.h"
#if PREFER_OPENSSL && OPENSSL_VERSION_MAJOR >= 3
#if HAVE_OPENSSL && OPENSSL_VERSION_MAJOR >= 3
DISABLE_WARNING_DEPRECATED_DECLARATIONS;
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(RSA*, RSA_free, NULL);
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(EC_KEY*, EC_KEY_free, NULL);
@@ -69,7 +68,7 @@ uint16_t dnssec_keytag(DnsResourceRecord *dnskey, bool mask_revoke) {
return sum & UINT32_C(0xFFFF);
}
#if HAVE_OPENSSL_OR_GCRYPT
#if HAVE_OPENSSL
static int rr_compare(DnsResourceRecord * const *a, DnsResourceRecord * const *b) {
const DnsResourceRecord *x = *a, *y = *b;
@@ -93,14 +92,13 @@ static int rr_compare(DnsResourceRecord * const *a, DnsResourceRecord * const *b
}
static int dnssec_rsa_verify_raw(
hash_algorithm_t hash_algorithm,
const EVP_MD *hash_algorithm,
const void *signature, size_t signature_size,
const void *data, size_t data_size,
const void *exponent, size_t exponent_size,
const void *modulus, size_t modulus_size) {
int r;
#if PREFER_OPENSSL
DISABLE_WARNING_DEPRECATED_DECLARATIONS;
_cleanup_(RSA_freep) RSA *rpubkey = NULL;
_cleanup_(EVP_PKEY_freep) EVP_PKEY *epubkey = NULL;
@@ -153,91 +151,11 @@ static int dnssec_rsa_verify_raw(
"Signature verification failed: 0x%lx", ERR_get_error());
REENABLE_WARNING;
#else
gcry_sexp_t public_key_sexp = NULL, data_sexp = NULL, signature_sexp = NULL;
gcry_mpi_t n = NULL, e = NULL, s = NULL;
gcry_error_t ge;
assert(hash_algorithm);
ge = gcry_mpi_scan(&s, GCRYMPI_FMT_USG, signature, signature_size, NULL);
if (ge != 0) {
r = -EIO;
goto finish;
}
ge = gcry_mpi_scan(&e, GCRYMPI_FMT_USG, exponent, exponent_size, NULL);
if (ge != 0) {
r = -EIO;
goto finish;
}
ge = gcry_mpi_scan(&n, GCRYMPI_FMT_USG, modulus, modulus_size, NULL);
if (ge != 0) {
r = -EIO;
goto finish;
}
ge = gcry_sexp_build(&signature_sexp,
NULL,
"(sig-val (rsa (s %m)))",
s);
if (ge != 0) {
r = -EIO;
goto finish;
}
ge = gcry_sexp_build(&data_sexp,
NULL,
"(data (flags pkcs1) (hash %s %b))",
hash_algorithm,
(int) data_size,
data);
if (ge != 0) {
r = -EIO;
goto finish;
}
ge = gcry_sexp_build(&public_key_sexp,
NULL,
"(public-key (rsa (n %m) (e %m)))",
n,
e);
if (ge != 0) {
r = -EIO;
goto finish;
}
ge = gcry_pk_verify(signature_sexp, data_sexp, public_key_sexp);
if (gpg_err_code(ge) == GPG_ERR_BAD_SIGNATURE)
r = 0;
else if (ge != 0)
r = log_debug_errno(SYNTHETIC_ERRNO(EIO),
"RSA signature check failed: %s", gpg_strerror(ge));
else
r = 1;
finish:
if (e)
gcry_mpi_release(e);
if (n)
gcry_mpi_release(n);
if (s)
gcry_mpi_release(s);
if (public_key_sexp)
gcry_sexp_release(public_key_sexp);
if (signature_sexp)
gcry_sexp_release(signature_sexp);
if (data_sexp)
gcry_sexp_release(data_sexp);
#endif
return r;
}
static int dnssec_rsa_verify(
hash_algorithm_t hash_algorithm,
const EVP_MD *hash_algorithm,
const void *hash, size_t hash_size,
DnsResourceRecord *rrsig,
DnsResourceRecord *dnskey) {
@@ -293,15 +211,14 @@ static int dnssec_rsa_verify(
}
static int dnssec_ecdsa_verify_raw(
hash_algorithm_t hash_algorithm,
elliptic_curve_t curve,
const EVP_MD *hash_algorithm,
int curve,
const void *signature_r, size_t signature_r_size,
const void *signature_s, size_t signature_s_size,
const void *data, size_t data_size,
const void *key, size_t key_size) {
int k;
#if PREFER_OPENSSL
DISABLE_WARNING_DEPRECATED_DECLARATIONS;
_cleanup_(EC_GROUP_freep) EC_GROUP *ec_group = NULL;
_cleanup_(EC_POINT_freep) EC_POINT *p = NULL;
@@ -364,96 +281,17 @@ static int dnssec_ecdsa_verify_raw(
"Signature verification failed: 0x%lx", ERR_get_error());
REENABLE_WARNING;
#else
gcry_sexp_t public_key_sexp = NULL, data_sexp = NULL, signature_sexp = NULL;
gcry_mpi_t q = NULL, r = NULL, s = NULL;
gcry_error_t ge;
assert(hash_algorithm);
ge = gcry_mpi_scan(&r, GCRYMPI_FMT_USG, signature_r, signature_r_size, NULL);
if (ge != 0) {
k = -EIO;
goto finish;
}
ge = gcry_mpi_scan(&s, GCRYMPI_FMT_USG, signature_s, signature_s_size, NULL);
if (ge != 0) {
k = -EIO;
goto finish;
}
ge = gcry_mpi_scan(&q, GCRYMPI_FMT_USG, key, key_size, NULL);
if (ge != 0) {
k = -EIO;
goto finish;
}
ge = gcry_sexp_build(&signature_sexp,
NULL,
"(sig-val (ecdsa (r %m) (s %m)))",
r,
s);
if (ge != 0) {
k = -EIO;
goto finish;
}
ge = gcry_sexp_build(&data_sexp,
NULL,
"(data (flags rfc6979) (hash %s %b))",
hash_algorithm,
(int) data_size,
data);
if (ge != 0) {
k = -EIO;
goto finish;
}
ge = gcry_sexp_build(&public_key_sexp,
NULL,
"(public-key (ecc (curve %s) (q %m)))",
curve,
q);
if (ge != 0) {
k = -EIO;
goto finish;
}
ge = gcry_pk_verify(signature_sexp, data_sexp, public_key_sexp);
if (gpg_err_code(ge) == GPG_ERR_BAD_SIGNATURE)
k = 0;
else if (ge != 0) {
log_debug("ECDSA signature check failed: %s", gpg_strerror(ge));
k = -EIO;
} else
k = 1;
finish:
if (r)
gcry_mpi_release(r);
if (s)
gcry_mpi_release(s);
if (q)
gcry_mpi_release(q);
if (public_key_sexp)
gcry_sexp_release(public_key_sexp);
if (signature_sexp)
gcry_sexp_release(signature_sexp);
if (data_sexp)
gcry_sexp_release(data_sexp);
#endif
return k;
}
static int dnssec_ecdsa_verify(
hash_algorithm_t hash_algorithm,
const EVP_MD *hash_algorithm,
int algorithm,
const void *hash, size_t hash_size,
DnsResourceRecord *rrsig,
DnsResourceRecord *dnskey) {
elliptic_curve_t curve;
int curve;
size_t key_size;
uint8_t *q;
@@ -463,10 +301,10 @@ static int dnssec_ecdsa_verify(
assert(dnskey);
if (algorithm == DNSSEC_ALGORITHM_ECDSAP256SHA256) {
curve = OPENSSL_OR_GCRYPT(NID_X9_62_prime256v1, "NIST P-256"); /* NIST P-256 */
curve = NID_X9_62_prime256v1; /* NIST P-256 */
key_size = 32;
} else if (algorithm == DNSSEC_ALGORITHM_ECDSAP384SHA384) {
curve = OPENSSL_OR_GCRYPT(NID_secp384r1, "NIST P-384"); /* NIST P-384 */
curve = NID_secp384r1; /* NIST P-384 */
key_size = 48;
} else
return -EOPNOTSUPP;
@@ -491,12 +329,11 @@ static int dnssec_ecdsa_verify(
}
static int dnssec_eddsa_verify_raw(
elliptic_curve_t curve,
int curve,
const uint8_t *signature, size_t signature_size,
const uint8_t *data, size_t data_size,
const uint8_t *key, size_t key_size) {
#if PREFER_OPENSSL
_cleanup_(EVP_PKEY_freep) EVP_PKEY *evkey = NULL;
_cleanup_(EVP_PKEY_CTX_freep) EVP_PKEY_CTX *pctx = NULL;
_cleanup_(EVP_MD_CTX_freep) EVP_MD_CTX *ctx = NULL;
@@ -535,67 +372,6 @@ static int dnssec_eddsa_verify_raw(
"Signature verification failed: 0x%lx", ERR_get_error());
return r;
#elif GCRYPT_VERSION_NUMBER >= 0x010600
gcry_sexp_t public_key_sexp = NULL, data_sexp = NULL, signature_sexp = NULL;
gcry_error_t ge;
int k;
assert(signature_size == key_size * 2);
ge = gcry_sexp_build(&signature_sexp,
NULL,
"(sig-val (eddsa (r %b) (s %b)))",
(int) key_size,
signature,
(int) key_size,
signature + key_size);
if (ge != 0) {
k = -EIO;
goto finish;
}
ge = gcry_sexp_build(&data_sexp,
NULL,
"(data (flags eddsa) (hash-algo sha512) (value %b))",
(int) data_size,
data);
if (ge != 0) {
k = -EIO;
goto finish;
}
ge = gcry_sexp_build(&public_key_sexp,
NULL,
"(public-key (ecc (curve %s) (flags eddsa) (q %b)))",
curve,
(int) key_size,
key);
if (ge != 0) {
k = -EIO;
goto finish;
}
ge = gcry_pk_verify(signature_sexp, data_sexp, public_key_sexp);
if (gpg_err_code(ge) == GPG_ERR_BAD_SIGNATURE)
k = 0;
else if (ge != 0)
k = log_debug_errno(SYNTHETIC_ERRNO(EIO),
"EdDSA signature check failed: %s", gpg_strerror(ge));
else
k = 1;
finish:
if (public_key_sexp)
gcry_sexp_release(public_key_sexp);
if (signature_sexp)
gcry_sexp_release(signature_sexp);
if (data_sexp)
gcry_sexp_release(data_sexp);
return k;
#else
return -EOPNOTSUPP;
#endif
}
static int dnssec_eddsa_verify(
@@ -603,11 +379,11 @@ static int dnssec_eddsa_verify(
const void *data, size_t data_size,
DnsResourceRecord *rrsig,
DnsResourceRecord *dnskey) {
elliptic_curve_t curve;
int curve;
size_t key_size;
if (algorithm == DNSSEC_ALGORITHM_ED25519) {
curve = OPENSSL_OR_GCRYPT(NID_ED25519, "Ed25519");
curve = NID_ED25519;
key_size = 32;
} else
return -EOPNOTSUPP;
@@ -625,23 +401,13 @@ static int dnssec_eddsa_verify(
dnskey->dnskey.key, key_size);
}
static int md_add_uint8(hash_context_t ctx, uint8_t v) {
#if PREFER_OPENSSL
static int md_add_uint8(EVP_MD_CTX *ctx, uint8_t v) {
return EVP_DigestUpdate(ctx, &v, sizeof(v));
#else
gcry_md_write(ctx, &v, sizeof(v));
return 0;
#endif
}
static int md_add_uint16(hash_context_t ctx, uint16_t v) {
static int md_add_uint16(EVP_MD_CTX *ctx, uint16_t v) {
v = htobe16(v);
#if PREFER_OPENSSL
return EVP_DigestUpdate(ctx, &v, sizeof(v));
#else
gcry_md_write(ctx, &v, sizeof(v));
return 0;
#endif
}
static void fwrite_uint8(FILE *fp, uint8_t v) {
@@ -746,9 +512,9 @@ static int dnssec_rrsig_expired(DnsResourceRecord *rrsig, usec_t realtime) {
return realtime < inception || realtime > expiration;
}
static hash_md_t algorithm_to_implementation_id(uint8_t algorithm) {
static const EVP_MD* algorithm_to_implementation_id(uint8_t algorithm) {
/* Translates a DNSSEC signature algorithm into an openssl/gcrypt digest identifier.
/* Translates a DNSSEC signature algorithm into an openssl digest identifier.
*
* Note that we implement all algorithms listed as "Must implement" and "Recommended to Implement" in
* RFC6944. We don't implement any algorithms that are listed as "Optional" or "Must Not Implement".
@@ -758,20 +524,20 @@ static hash_md_t algorithm_to_implementation_id(uint8_t algorithm) {
case DNSSEC_ALGORITHM_RSASHA1:
case DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1:
return OPENSSL_OR_GCRYPT(EVP_sha1(), GCRY_MD_SHA1);
return EVP_sha1();
case DNSSEC_ALGORITHM_RSASHA256:
case DNSSEC_ALGORITHM_ECDSAP256SHA256:
return OPENSSL_OR_GCRYPT(EVP_sha256(), GCRY_MD_SHA256);
return EVP_sha256();
case DNSSEC_ALGORITHM_ECDSAP384SHA384:
return OPENSSL_OR_GCRYPT(EVP_sha384(), GCRY_MD_SHA384);
return EVP_sha384();
case DNSSEC_ALGORITHM_RSASHA512:
return OPENSSL_OR_GCRYPT(EVP_sha512(), GCRY_MD_SHA512);
return EVP_sha512();
default:
return OPENSSL_OR_GCRYPT(NULL, -EOPNOTSUPP);
return NULL;
}
}
@@ -879,37 +645,23 @@ static int dnssec_rrset_verify_sig(
assert(sig_data);
assert(sig_size > 0);
hash_md_t md_algorithm;
const EVP_MD *md_algorithm;
#if PREFER_OPENSSL
uint8_t hash[EVP_MAX_MD_SIZE];
unsigned hash_size;
#else
_cleanup_(gcry_md_closep) gcry_md_hd_t md = NULL;
void *hash;
size_t hash_size;
int r;
r = initialize_libgcrypt(false);
if (r < 0)
return r;
#endif
switch (rrsig->rrsig.algorithm) {
case DNSSEC_ALGORITHM_ED25519:
#if PREFER_OPENSSL || GCRYPT_VERSION_NUMBER >= 0x010600
return dnssec_eddsa_verify(
rrsig->rrsig.algorithm,
sig_data, sig_size,
rrsig,
dnskey);
#endif
case DNSSEC_ALGORITHM_ED448:
return -EOPNOTSUPP;
default:
/* OK, the RRs are now in canonical order. Let's calculate the digest */
md_algorithm = algorithm_to_implementation_id(rrsig->rrsig.algorithm);
#if PREFER_OPENSSL
if (!md_algorithm)
return -EOPNOTSUPP;
@@ -927,24 +679,6 @@ static int dnssec_rrset_verify_sig(
return -EIO;
assert(hash_size > 0);
#else
if (md_algorithm < 0)
return md_algorithm;
gcry_error_t err = gcry_md_open(&md, md_algorithm, 0);
if (gcry_err_code(err) != GPG_ERR_NO_ERROR || !md)
return -EIO;
hash_size = gcry_md_get_algo_dlen(md_algorithm);
assert(hash_size > 0);
gcry_md_write(md, sig_data, sig_size);
hash = gcry_md_read(md, 0);
if (!hash)
return -EIO;
#endif
}
switch (rrsig->rrsig.algorithm) {
@@ -954,7 +688,7 @@ static int dnssec_rrset_verify_sig(
case DNSSEC_ALGORITHM_RSASHA256:
case DNSSEC_ALGORITHM_RSASHA512:
return dnssec_rsa_verify(
OPENSSL_OR_GCRYPT(md_algorithm, gcry_md_algo_name(md_algorithm)),
md_algorithm,
hash, hash_size,
rrsig,
dnskey);
@@ -962,7 +696,7 @@ static int dnssec_rrset_verify_sig(
case DNSSEC_ALGORITHM_ECDSAP256SHA256:
case DNSSEC_ALGORITHM_ECDSAP384SHA384:
return dnssec_ecdsa_verify(
OPENSSL_OR_GCRYPT(md_algorithm, gcry_md_algo_name(md_algorithm)),
md_algorithm,
rrsig->rrsig.algorithm,
hash, hash_size,
rrsig,
@@ -1313,23 +1047,23 @@ int dnssec_has_rrsig(DnsAnswer *a, const DnsResourceKey *key) {
return 0;
}
static hash_md_t digest_to_hash_md(uint8_t algorithm) {
static const EVP_MD* digest_to_hash_md(uint8_t algorithm) {
/* Translates a DNSSEC digest algorithm into an openssl/gcrypt digest identifier */
/* Translates a DNSSEC digest algorithm into an openssl digest identifier */
switch (algorithm) {
case DNSSEC_DIGEST_SHA1:
return OPENSSL_OR_GCRYPT(EVP_sha1(), GCRY_MD_SHA1);
return EVP_sha1();
case DNSSEC_DIGEST_SHA256:
return OPENSSL_OR_GCRYPT(EVP_sha256(), GCRY_MD_SHA256);
return EVP_sha256();
case DNSSEC_DIGEST_SHA384:
return OPENSSL_OR_GCRYPT(EVP_sha384(), GCRY_MD_SHA384);
return EVP_sha384();
default:
return OPENSSL_OR_GCRYPT(NULL, -EOPNOTSUPP);
return NULL;
}
}
@@ -1364,9 +1098,7 @@ int dnssec_verify_dnskey_by_ds(DnsResourceRecord *dnskey, DnsResourceRecord *ds,
return r;
encoded_length = r;
hash_md_t md_algorithm = digest_to_hash_md(ds->ds.digest_type);
#if PREFER_OPENSSL
const EVP_MD *md_algorithm = digest_to_hash_md(ds->ds.digest_type);
if (!md_algorithm)
return -EOPNOTSUPP;
@@ -1406,40 +1138,6 @@ int dnssec_verify_dnskey_by_ds(DnsResourceRecord *dnskey, DnsResourceRecord *ds,
if (EVP_DigestFinal_ex(ctx, result, NULL) <= 0)
return -EIO;
#else
if (md_algorithm < 0)
return -EOPNOTSUPP;
r = initialize_libgcrypt(false);
if (r < 0)
return r;
_cleanup_(gcry_md_closep) gcry_md_hd_t md = NULL;
size_t hash_size = gcry_md_get_algo_dlen(md_algorithm);
assert(hash_size > 0);
if (ds->ds.digest_size != hash_size)
return 0;
gcry_error_t err = gcry_md_open(&md, md_algorithm, 0);
if (gcry_err_code(err) != GPG_ERR_NO_ERROR || !md)
return -EIO;
gcry_md_write(md, wire_format, encoded_length);
if (mask_revoke)
md_add_uint16(md, dnskey->dnskey.flags & ~DNSKEY_FLAG_REVOKE);
else
md_add_uint16(md, dnskey->dnskey.flags);
md_add_uint8(md, dnskey->dnskey.protocol);
md_add_uint8(md, dnskey->dnskey.algorithm);
gcry_md_write(md, dnskey->dnskey.key, dnskey->dnskey.key_size);
void *result = gcry_md_read(md, 0);
if (!result)
return -EIO;
#endif
return memcmp(result, ds->ds.digest, ds->ds.digest_size) == 0;
}
@@ -1481,17 +1179,17 @@ int dnssec_verify_dnskey_by_ds_search(DnsResourceRecord *dnskey, DnsAnswer *vali
return 0;
}
static hash_md_t nsec3_hash_to_hash_md(uint8_t algorithm) {
static const EVP_MD* nsec3_hash_to_hash_md(uint8_t algorithm) {
/* Translates a DNSSEC NSEC3 hash algorithm into an openssl/gcrypt digest identifier */
/* Translates a DNSSEC NSEC3 hash algorithm into an openssl digest identifier */
switch (algorithm) {
case NSEC3_ALGORITHM_SHA1:
return OPENSSL_OR_GCRYPT(EVP_sha1(), GCRY_MD_SHA1);
return EVP_sha1();
default:
return OPENSSL_OR_GCRYPT(NULL, -EOPNOTSUPP);
return NULL;
}
}
@@ -1511,8 +1209,7 @@ int dnssec_nsec3_hash(DnsResourceRecord *nsec3, const char *name, void *ret) {
"Ignoring NSEC3 RR %s with excessive number of iterations.",
dns_resource_record_to_string(nsec3));
hash_md_t algorithm = nsec3_hash_to_hash_md(nsec3->nsec3.algorithm);
#if PREFER_OPENSSL
const EVP_MD *algorithm = nsec3_hash_to_hash_md(nsec3->nsec3.algorithm);
if (!algorithm)
return -EOPNOTSUPP;
@@ -1553,51 +1250,6 @@ int dnssec_nsec3_hash(DnsResourceRecord *nsec3, const char *name, void *ret) {
if (EVP_DigestFinal_ex(ctx, result, NULL) <= 0)
return -EIO;
}
#else
if (algorithm < 0)
return algorithm;
r = initialize_libgcrypt(false);
if (r < 0)
return r;
size_t encoded_length;
unsigned hash_size = gcry_md_get_algo_dlen(algorithm);
assert(hash_size > 0);
if (nsec3->nsec3.next_hashed_name_size != hash_size)
return -EINVAL;
r = dns_name_to_wire_format(name, wire_format, sizeof(wire_format), true);
if (r < 0)
return r;
encoded_length = r;
_cleanup_(gcry_md_closep) gcry_md_hd_t md = NULL;
gcry_error_t err = gcry_md_open(&md, algorithm, 0);
if (gcry_err_code(err) != GPG_ERR_NO_ERROR || !md)
return -EIO;
gcry_md_write(md, wire_format, encoded_length);
gcry_md_write(md, nsec3->nsec3.salt, nsec3->nsec3.salt_size);
void *result = gcry_md_read(md, 0);
if (!result)
return -EIO;
for (unsigned k = 0; k < nsec3->nsec3.iterations; k++) {
uint8_t tmp[hash_size];
memcpy(tmp, result, hash_size);
gcry_md_reset(md);
gcry_md_write(md, tmp, hash_size);
gcry_md_write(md, nsec3->nsec3.salt, nsec3->nsec3.salt_size);
result = gcry_md_read(md, 0);
if (!result)
return -EIO;
}
#endif
memcpy(ret, result, hash_size);
return (int) hash_size;
@@ -1617,13 +1269,8 @@ static int nsec3_is_good(DnsResourceRecord *rr, DnsResourceRecord *nsec3) {
return 0;
/* Ignore NSEC3 RRs whose algorithm we don't know */
#if PREFER_OPENSSL
if (!nsec3_hash_to_hash_md(rr->nsec3.algorithm))
return 0;
#else
if (nsec3_hash_to_hash_md(rr->nsec3.algorithm) < 0)
return 0;
#endif
/* Ignore NSEC3 RRs with an excessive number of required iterations */
if (rr->nsec3.iterations > NSEC3_ITERATIONS_MAX)

View File

@@ -1,9 +1,5 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#if HAVE_GCRYPT
# include <gcrypt.h>
#endif
#include "alloc-util.h"
#include "dns-domain.h"
#include "escape.h"
@@ -814,7 +810,7 @@ int dns_packet_append_opt(
static const uint8_t rfc6975[] = {
0, DNS_EDNS_OPT_DAU, /* OPTION_CODE */
#if PREFER_OPENSSL || (HAVE_GCRYPT && GCRYPT_VERSION_NUMBER >= 0x010600)
#if HAVE_OPENSSL
0, 7, /* LIST_LENGTH */
#else
0, 6, /* LIST_LENGTH */
@@ -825,7 +821,7 @@ int dns_packet_append_opt(
DNSSEC_ALGORITHM_RSASHA512,
DNSSEC_ALGORITHM_ECDSAP256SHA256,
DNSSEC_ALGORITHM_ECDSAP384SHA384,
#if PREFER_OPENSSL || (HAVE_GCRYPT && GCRYPT_VERSION_NUMBER >= 0x010600)
#if HAVE_OPENSSL
DNSSEC_ALGORITHM_ED25519,
#endif

View File

@@ -1,255 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#if !ENABLE_DNS_OVER_TLS || !DNS_OVER_TLS_USE_GNUTLS
#error This source file requires DNS-over-TLS to be enabled and GnuTLS to be available.
#endif
#include <gnutls/socket.h>
#include "iovec-util.h"
#include "resolved-dns-stream.h"
#include "resolved-dnstls.h"
#include "resolved-manager.h"
#define TLS_PROTOCOL_PRIORITY "NORMAL:-VERS-ALL:+VERS-TLS1.3:+VERS-TLS1.2"
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(gnutls_session_t, gnutls_deinit, NULL);
static ssize_t dnstls_stream_vec_push(gnutls_transport_ptr_t p, const giovec_t *iov, int iovcnt) {
int r;
assert(p);
r = dns_stream_writev((DnsStream*) p, (const struct iovec*) iov, iovcnt, DNS_STREAM_WRITE_TLS_DATA);
if (r < 0) {
errno = -r;
return -1;
}
return r;
}
int dnstls_stream_connect_tls(DnsStream *stream, DnsServer *server) {
_cleanup_(gnutls_deinitp) gnutls_session_t gs = NULL;
int r;
assert(stream);
assert(server);
r = gnutls_init(&gs, GNUTLS_CLIENT | GNUTLS_ENABLE_FALSE_START | GNUTLS_NONBLOCK);
if (r < 0)
return r;
/* As DNS-over-TLS is a recent protocol, older TLS versions can be disabled */
r = gnutls_priority_set_direct(gs, TLS_PROTOCOL_PRIORITY, NULL);
if (r < 0)
return r;
r = gnutls_credentials_set(gs, GNUTLS_CRD_CERTIFICATE, stream->manager->dnstls_data.cert_cred);
if (r < 0)
return r;
if (server->dnstls_data.session_data.size > 0) {
gnutls_session_set_data(gs, server->dnstls_data.session_data.data, server->dnstls_data.session_data.size);
// Clear old session ticket
gnutls_free(server->dnstls_data.session_data.data);
server->dnstls_data.session_data.data = NULL;
server->dnstls_data.session_data.size = 0;
}
if (server->manager->dns_over_tls_mode == DNS_OVER_TLS_YES) {
if (server->server_name)
gnutls_session_set_verify_cert(gs, server->server_name, 0);
else {
stream->dnstls_data.validation.type = GNUTLS_DT_IP_ADDRESS;
if (server->family == AF_INET) {
stream->dnstls_data.validation.data = (unsigned char*) &server->address.in.s_addr;
stream->dnstls_data.validation.size = 4;
} else {
stream->dnstls_data.validation.data = server->address.in6.s6_addr;
stream->dnstls_data.validation.size = 16;
}
gnutls_session_set_verify_cert2(gs, &stream->dnstls_data.validation, 1, 0);
}
}
if (server->server_name) {
r = gnutls_server_name_set(gs, GNUTLS_NAME_DNS, server->server_name, strlen(server->server_name));
if (r < 0)
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to set server name: %s", gnutls_strerror(r));
}
gnutls_handshake_set_timeout(gs, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
gnutls_transport_set_ptr2(gs, (gnutls_transport_ptr_t) (long) stream->fd, stream);
gnutls_transport_set_vec_push_function(gs, &dnstls_stream_vec_push);
stream->encrypted = true;
stream->dnstls_data.handshake = gnutls_handshake(gs);
if (stream->dnstls_data.handshake < 0 && gnutls_error_is_fatal(stream->dnstls_data.handshake))
return -ECONNREFUSED;
stream->dnstls_data.session = TAKE_PTR(gs);
return 0;
}
void dnstls_stream_free(DnsStream *stream) {
assert(stream);
assert(stream->encrypted);
if (stream->dnstls_data.session)
gnutls_deinit(stream->dnstls_data.session);
}
int dnstls_stream_on_io(DnsStream *stream, uint32_t revents) {
int r;
assert(stream);
assert(stream->encrypted);
assert(stream->dnstls_data.session);
if (stream->dnstls_data.shutdown) {
r = gnutls_bye(stream->dnstls_data.session, GNUTLS_SHUT_RDWR);
if (r == GNUTLS_E_AGAIN) {
stream->dnstls_events = gnutls_record_get_direction(stream->dnstls_data.session) == 1 ? EPOLLOUT : EPOLLIN;
return -EAGAIN;
} else if (r < 0)
log_debug("Failed to invoke gnutls_bye: %s", gnutls_strerror(r));
stream->dnstls_events = 0;
stream->dnstls_data.shutdown = false;
dns_stream_unref(stream);
return DNSTLS_STREAM_CLOSED;
} else if (stream->dnstls_data.handshake < 0) {
stream->dnstls_data.handshake = gnutls_handshake(stream->dnstls_data.session);
if (stream->dnstls_data.handshake == GNUTLS_E_AGAIN) {
stream->dnstls_events = gnutls_record_get_direction(stream->dnstls_data.session) == 1 ? EPOLLOUT : EPOLLIN;
return -EAGAIN;
} else if (stream->dnstls_data.handshake < 0) {
log_debug("Failed to invoke gnutls_handshake: %s", gnutls_strerror(stream->dnstls_data.handshake));
if (gnutls_error_is_fatal(stream->dnstls_data.handshake))
return -ECONNREFUSED;
}
stream->dnstls_events = 0;
}
return 0;
}
int dnstls_stream_shutdown(DnsStream *stream, int error) {
int r;
assert(stream);
assert(stream->encrypted);
assert(stream->dnstls_data.session);
/* Store TLS Ticket for faster successive TLS handshakes */
if (stream->server && stream->server->dnstls_data.session_data.size == 0 && stream->dnstls_data.handshake == GNUTLS_E_SUCCESS)
gnutls_session_get_data2(stream->dnstls_data.session, &stream->server->dnstls_data.session_data);
if (IN_SET(error, ETIMEDOUT, 0)) {
r = gnutls_bye(stream->dnstls_data.session, GNUTLS_SHUT_RDWR);
if (r == GNUTLS_E_AGAIN) {
if (!stream->dnstls_data.shutdown) {
stream->dnstls_data.shutdown = true;
dns_stream_ref(stream);
return -EAGAIN;
}
} else if (r < 0)
log_debug("Failed to invoke gnutls_bye: %s", gnutls_strerror(r));
}
return 0;
}
ssize_t dnstls_stream_writev(DnsStream *stream, const struct iovec *iov, size_t iovcnt) {
ssize_t ss;
assert(stream);
assert(stream->encrypted);
assert(stream->dnstls_data.session);
assert(iov);
assert(iovec_total_size(iov, iovcnt) > 0);
gnutls_record_cork(stream->dnstls_data.session);
for (size_t i = 0; i < iovcnt; i++) {
ss = gnutls_record_send(
stream->dnstls_data.session,
iov[i].iov_base, iov[i].iov_len);
if (ss < 0)
break;
}
ss = gnutls_record_uncork(stream->dnstls_data.session, 0);
if (ss < 0)
switch (ss) {
case GNUTLS_E_INTERRUPTED:
return -EINTR;
case GNUTLS_E_AGAIN:
return -EAGAIN;
default:
return log_debug_errno(SYNTHETIC_ERRNO(EPIPE),
"Failed to invoke gnutls_record_send: %s",
gnutls_strerror(ss));
}
return ss;
}
ssize_t dnstls_stream_read(DnsStream *stream, void *buf, size_t count) {
ssize_t ss;
assert(stream);
assert(stream->encrypted);
assert(stream->dnstls_data.session);
assert(buf);
ss = gnutls_record_recv(stream->dnstls_data.session, buf, count);
if (ss < 0)
switch (ss) {
case GNUTLS_E_INTERRUPTED:
return -EINTR;
case GNUTLS_E_AGAIN:
return -EAGAIN;
default:
return log_debug_errno(SYNTHETIC_ERRNO(EPIPE),
"Failed to invoke gnutls_record_recv: %s",
gnutls_strerror(ss));
}
return ss;
}
void dnstls_server_free(DnsServer *server) {
assert(server);
if (server->dnstls_data.session_data.data)
gnutls_free(server->dnstls_data.session_data.data);
}
int dnstls_manager_init(Manager *manager) {
int r;
assert(manager);
r = gnutls_certificate_allocate_credentials(&manager->dnstls_data.cert_cred);
if (r < 0)
return log_warning_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
"Failed to allocate SSL credentials: %s",
gnutls_strerror(r));
r = gnutls_certificate_set_x509_system_trust(manager->dnstls_data.cert_cred);
if (r < 0)
log_warning("Failed to load system trust store: %s", gnutls_strerror(r));
return 0;
}
void dnstls_manager_free(Manager *manager) {
assert(manager);
if (manager->dnstls_data.cert_cred)
gnutls_certificate_free_credentials(manager->dnstls_data.cert_cred);
}

View File

@@ -1,24 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#if !ENABLE_DNS_OVER_TLS || !DNS_OVER_TLS_USE_GNUTLS
#error This source file requires DNS-over-TLS to be enabled and GnuTLS to be available.
#endif
#include <gnutls/gnutls.h>
#include <stdbool.h>
struct DnsTlsManagerData {
gnutls_certificate_credentials_t cert_cred;
};
struct DnsTlsServerData {
gnutls_datum_t session_data;
};
struct DnsTlsStreamData {
gnutls_session_t session;
gnutls_typed_vdata_st validation;
int handshake;
bool shutdown;
};

View File

@@ -1,25 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#if !ENABLE_DNS_OVER_TLS || !DNS_OVER_TLS_USE_OPENSSL
#error This source file requires DNS-over-TLS to be enabled and OpenSSL to be available.
#endif
#include <openssl/ssl.h>
#include <stdbool.h>
struct DnsTlsManagerData {
SSL_CTX *ctx;
};
struct DnsTlsServerData {
SSL_SESSION *session;
};
struct DnsTlsStreamData {
int handshake;
bool shutdown;
SSL *ssl;
BUF_MEM *write_buffer;
size_t buffer_offset;
};

View File

@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#if !ENABLE_DNS_OVER_TLS || !DNS_OVER_TLS_USE_OPENSSL
#if !ENABLE_DNS_OVER_TLS || !HAVE_OPENSSL
#error This source file requires DNS-over-TLS to be enabled and OpenSSL to be available.
#endif

View File

@@ -3,23 +3,34 @@
#if ENABLE_DNS_OVER_TLS
#if !HAVE_OPENSSL
#error This source file requires OpenSSL to be available.
#endif
#include <openssl/ssl.h>
#include <stdbool.h>
#include <stdint.h>
#include <sys/uio.h>
typedef struct DnsServer DnsServer;
typedef struct DnsStream DnsStream;
typedef struct DnsTlsManagerData DnsTlsManagerData;
typedef struct DnsTlsServerData DnsTlsServerData;
typedef struct DnsTlsStreamData DnsTlsStreamData;
typedef struct Manager Manager;
#if DNS_OVER_TLS_USE_GNUTLS
#include "resolved-dnstls-gnutls.h"
#elif DNS_OVER_TLS_USE_OPENSSL
#include "resolved-dnstls-openssl.h"
#else
#error Unknown dependency for supporting DNS-over-TLS
#endif
typedef struct DnsTlsManagerData {
SSL_CTX *ctx;
} DnsTlsManagerData;
typedef struct DnsTlsServerData {
SSL_SESSION *session;
} DnsTlsServerData;
typedef struct DnsTlsStreamData {
int handshake;
bool shutdown;
SSL *ssl;
BUF_MEM *write_buffer;
size_t buffer_offset;
} DnsTlsStreamData;
#define DNSTLS_STREAM_CLOSED 1

View File

@@ -418,11 +418,11 @@ void link_set_dnssec_mode(Link *l, DnssecMode mode) {
assert(l);
#if !HAVE_OPENSSL_OR_GCRYPT
#if !HAVE_OPENSSL
if (IN_SET(mode, DNSSEC_YES, DNSSEC_ALLOW_DOWNGRADE))
log_link_warning(l,
"DNSSEC option for the link cannot be enabled or set to allow-downgrade "
"when systemd-resolved is built without a cryptographic library. "
"when systemd-resolved is built without openssl. "
"Turning off DNSSEC support.");
return;
#endif

View File

@@ -4,10 +4,6 @@
#include <netinet/in.h>
#include <sys/socket.h>
#if HAVE_GCRYPT
# include <gcrypt.h>
#endif
#include "alloc-util.h"
#include "hexdecoct.h"
#include "resolved-dns-dnssec.h"
@@ -173,11 +169,7 @@ TEST(dnssec_verify_rfc8080_ed25519_example1) {
assert_se(dnssec_verify_rrset(answer, mx->key, rrsig, dnskey,
rrsig->rrsig.inception * USEC_PER_SEC, &result) >= 0);
#if PREFER_OPENSSL || GCRYPT_VERSION_NUMBER >= 0x010600
assert_se(result == DNSSEC_VALIDATED);
#else
assert_se(result == DNSSEC_UNSUPPORTED_ALGORITHM);
#endif
}
TEST(dnssec_verify_rfc8080_ed25519_example2) {
@@ -265,11 +257,7 @@ TEST(dnssec_verify_rfc8080_ed25519_example2) {
assert_se(dnssec_verify_rrset(answer, mx->key, rrsig, dnskey,
rrsig->rrsig.inception * USEC_PER_SEC, &result) >= 0);
#if PREFER_OPENSSL || GCRYPT_VERSION_NUMBER >= 0x010600
assert_se(result == DNSSEC_VALIDATED);
#else
assert_se(result == DNSSEC_UNSUPPORTED_ALGORITHM);
#endif
}
TEST(dnssec_verify_rfc6605_example1) {

View File

@@ -1224,7 +1224,6 @@ int pkcs7_new(X509 *certificate, EVP_PKEY *private_key, PKCS7 **ret_p7, PKCS7_SI
return 0;
}
# if PREFER_OPENSSL
int string_hashsum(
const char *s,
size_t len,
@@ -1251,7 +1250,6 @@ int string_hashsum(
*ret = TAKE_PTR(enc);
return 0;
}
# endif
static int ecc_pkey_generate_volume_keys(
EVP_PKEY *pkey,

View File

@@ -169,6 +169,8 @@ int digest_and_sign(const EVP_MD *md, EVP_PKEY *privkey, const void *data, size_
int pkcs7_new(X509 *certificate, EVP_PKEY *private_key, PKCS7 **ret_p7, PKCS7_SIGNER_INFO **ret_si);
int string_hashsum(const char *s, size_t len, const char *md_algorithm, char **ret);
#else
typedef struct X509 X509;
@@ -198,6 +200,10 @@ static inline void* ASN1_STRING_free(ASN1_STRING *p) {
return NULL;
}
static inline int string_hashsum(const char *s, size_t len, const char *md_algorithm, char **ret) {
return -EOPNOTSUPP;
}
#endif
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(X509*, X509_free, NULL);
@@ -230,29 +236,6 @@ int openssl_load_private_key(
EVP_PKEY **ret_private_key,
OpenSSLAskPasswordUI **ret_user_interface);
#if PREFER_OPENSSL
/* The openssl definition */
typedef const EVP_MD* hash_md_t;
typedef const EVP_MD* hash_algorithm_t;
typedef int elliptic_curve_t;
typedef EVP_MD_CTX* hash_context_t;
# define OPENSSL_OR_GCRYPT(a, b) (a)
#elif HAVE_GCRYPT
# include <gcrypt.h>
/* The gcrypt definition */
typedef int hash_md_t;
typedef const char* hash_algorithm_t;
typedef const char* elliptic_curve_t;
typedef gcry_md_hd_t hash_context_t;
# define OPENSSL_OR_GCRYPT(a, b) (b)
#endif
#if PREFER_OPENSSL
int string_hashsum(const char *s, size_t len, const char *md_algorithm, char **ret);
static inline int string_hashsum_sha224(const char *s, size_t len, char **ret) {
return string_hashsum(s, len, "SHA224", ret);
}
@@ -260,4 +243,3 @@ static inline int string_hashsum_sha224(const char *s, size_t len, char **ret) {
static inline int string_hashsum_sha256(const char *s, size_t len, char **ret) {
return string_hashsum(s, len, "SHA256", ret);
}
#endif

View File

@@ -268,8 +268,8 @@ executables += [
},
test_template + {
'sources' : files('test-cryptolib.c'),
'dependencies' : lib_openssl_or_gcrypt,
'conditions' : ['HAVE_OPENSSL_OR_GCRYPT'],
'dependencies' : libopenssl,
'conditions' : ['HAVE_OPENSSL'],
},
test_template + {
'sources' : files('test-display-quota.c'),

View File

@@ -1,7 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "alloc-util.h"
#include "gcrypt-util.h"
#include "macro.h"
#include "openssl-util.h"
#include "string-util.h"
@@ -11,25 +10,25 @@ TEST(string_hashsum) {
_cleanup_free_ char *out1 = NULL, *out2 = NULL, *out3 = NULL, *out4 = NULL;
assert_se(string_hashsum("asdf", 4,
OPENSSL_OR_GCRYPT("SHA224", GCRY_MD_SHA224),
"SHA224",
&out1) == 0);
/* echo -n 'asdf' | sha224sum - */
ASSERT_STREQ(out1, "7872a74bcbf298a1e77d507cd95d4f8d96131cbbd4cdfc571e776c8a");
assert_se(string_hashsum("asdf", 4,
OPENSSL_OR_GCRYPT("SHA256", GCRY_MD_SHA256),
"SHA256",
&out2) == 0);
/* echo -n 'asdf' | sha256sum - */
ASSERT_STREQ(out2, "f0e4c2f76c58916ec258f246851bea091d14d4247a2fc3e18694461b1816e13b");
assert_se(string_hashsum("", 0,
OPENSSL_OR_GCRYPT("SHA224", GCRY_MD_SHA224),
"SHA224",
&out3) == 0);
/* echo -n '' | sha224sum - */
ASSERT_STREQ(out3, "d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f");
assert_se(string_hashsum("", 0,
OPENSSL_OR_GCRYPT("SHA256", GCRY_MD_SHA256),
"SHA256",
&out4) == 0);
/* echo -n '' | sha256sum - */
ASSERT_STREQ(out4, "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855");