mirror of
https://github.com/systemd/systemd-stable.git
synced 2025-01-21 18:03:41 +03:00
Merge pull request #21170 from keszybz/delibgcryptify
Allow systemd-resolved and systemd-importd to use libgcrypt or libopenssl
This commit is contained in:
commit
939387bdc6
2
.github/workflows/unit_tests.sh
vendored
2
.github/workflows/unit_tests.sh
vendored
@ -29,6 +29,8 @@ function info() {
|
|||||||
|
|
||||||
set -ex
|
set -ex
|
||||||
|
|
||||||
|
MESON_ARGS=(-Dcryptolib=${CRYPTOLIB:-auto})
|
||||||
|
|
||||||
for phase in "${PHASES[@]}"; do
|
for phase in "${PHASES[@]}"; do
|
||||||
case $phase in
|
case $phase in
|
||||||
SETUP)
|
SETUP)
|
||||||
|
10
.github/workflows/unit_tests.yml
vendored
10
.github/workflows/unit_tests.yml
vendored
@ -22,10 +22,18 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
run_phase: [GCC, GCC_ASAN_UBSAN, CLANG, CLANG_ASAN_UBSAN]
|
run_phase: [GCC, GCC_ASAN_UBSAN, CLANG, CLANG_ASAN_UBSAN]
|
||||||
|
cryptolib: [auto]
|
||||||
|
include:
|
||||||
|
- run_phase: GCC
|
||||||
|
cryptolib: openssl
|
||||||
|
- run_phase: CLANG
|
||||||
|
cryptolib: gcrypt
|
||||||
steps:
|
steps:
|
||||||
- name: Repository checkout
|
- name: Repository checkout
|
||||||
uses: actions/checkout@ec3a7ce113134d7a93b817d10a8272cb61118579
|
uses: actions/checkout@ec3a7ce113134d7a93b817d10a8272cb61118579
|
||||||
- name: Install build dependencies
|
- name: Install build dependencies
|
||||||
run: sudo -E .github/workflows/unit_tests.sh SETUP
|
run: sudo -E .github/workflows/unit_tests.sh SETUP
|
||||||
- name: Build & test (${{ matrix.run_phase }})
|
- name: Build & test (${{ matrix.run_phase }}-${{ matrix.cryptolib }})
|
||||||
run: sudo -E .github/workflows/unit_tests.sh RUN_${{ matrix.run_phase }}
|
run: sudo -E .github/workflows/unit_tests.sh RUN_${{ matrix.run_phase }}
|
||||||
|
env:
|
||||||
|
CRYPTOLIB: ${{ matrix.cryptolib }}
|
||||||
|
@ -31,6 +31,9 @@ actions:
|
|||||||
# [0] https://github.com/mesonbuild/meson/issues/7360
|
# [0] https://github.com/mesonbuild/meson/issues/7360
|
||||||
# [1] https://github.com/systemd/systemd/pull/18908#issuecomment-792250110
|
# [1] https://github.com/systemd/systemd/pull/18908#issuecomment-792250110
|
||||||
- 'sed -i "/^CONFIGURE_OPTS=(/a--werror" .packit_rpm/systemd.spec'
|
- 'sed -i "/^CONFIGURE_OPTS=(/a--werror" .packit_rpm/systemd.spec'
|
||||||
|
# FIXME: temporarily disable the deprecated-declarations check to suppress
|
||||||
|
# OpenSSL 3.0 warnings in Rawhide
|
||||||
|
- 'sed -i "1 i %global optflags %{optflags} -Wno-deprecated-declarations" .packit_rpm/systemd.spec'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
- job: copr_build
|
- job: copr_build
|
||||||
|
5
TODO
5
TODO
@ -432,11 +432,8 @@ Features:
|
|||||||
* socket units: allow creating a udev monitor socket with ListenDevices= or so,
|
* socket units: allow creating a udev monitor socket with ListenDevices= or so,
|
||||||
with matches, then activate app through that passing socket over
|
with matches, then activate app through that passing socket over
|
||||||
|
|
||||||
* unify on openssl (as soon as OpenSSL 3.0 is out, and the Debian license
|
* unify on openssl:
|
||||||
confusion is gone)
|
|
||||||
- port resolved over from libgcrypt (DNSSEC code)
|
|
||||||
- port journald + fsprg over from libgcrypt
|
- port journald + fsprg over from libgcrypt
|
||||||
- port importd over from libgcrypt
|
|
||||||
- when that's done: kill gnutls support in resolved
|
- when that's done: kill gnutls support in resolved
|
||||||
|
|
||||||
* add growvol and makevol options for /etc/crypttab, similar to
|
* add growvol and makevol options for /etc/crypttab, similar to
|
||||||
|
55
meson.build
55
meson.build
@ -1448,21 +1448,25 @@ else
|
|||||||
endif
|
endif
|
||||||
conf.set10('HAVE_DBUS', have)
|
conf.set10('HAVE_DBUS', have)
|
||||||
|
|
||||||
default_dnssec = get_option('default-dnssec')
|
# We support one or the other. If gcrypt is available, we assume it's there to
|
||||||
if skip_deps
|
# be used, and use it in preference.
|
||||||
default_dnssec = 'no'
|
opt = get_option('cryptolib')
|
||||||
|
if opt == 'openssl' and conf.get('HAVE_OPENSSL') == 0
|
||||||
|
error('openssl requested as the default cryptolib, but not available')
|
||||||
endif
|
endif
|
||||||
if default_dnssec != 'no' and conf.get('HAVE_GCRYPT') == 0
|
conf.set10('PREFER_OPENSSL',
|
||||||
message('default-dnssec cannot be set to yes or allow-downgrade when gcrypt is disabled. Setting default-dnssec to no.')
|
opt == 'openssl' or (opt == 'auto' and conf.get('HAVE_OPENSSL') == 1 and conf.get('HAVE_GCRYPT') == 0))
|
||||||
default_dnssec = 'no'
|
conf.set10('HAVE_OPENSSL_OR_GCRYPT',
|
||||||
endif
|
conf.get('HAVE_OPENSSL') == 1 or conf.get('HAVE_GCRYPT') == 1)
|
||||||
conf.set('DEFAULT_DNSSEC_MODE',
|
lib_openssl_or_gcrypt = conf.get('PREFER_OPENSSL') == 1 ? libopenssl : libgcrypt
|
||||||
'DNSSEC_' + default_dnssec.underscorify().to_upper())
|
|
||||||
conf.set_quoted('DEFAULT_DNSSEC_MODE_STR', default_dnssec)
|
|
||||||
|
|
||||||
dns_over_tls = get_option('dns-over-tls')
|
dns_over_tls = get_option('dns-over-tls')
|
||||||
if dns_over_tls != 'false'
|
if dns_over_tls != 'false'
|
||||||
if dns_over_tls == 'openssl'
|
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 == 'openssl' or conf.get('PREFER_OPENSSL') == 1
|
||||||
have_gnutls = false
|
have_gnutls = false
|
||||||
else
|
else
|
||||||
have_gnutls = (conf.get('HAVE_GNUTLS') == 1 and libgnutls.version().version_compare('>= 3.6.0'))
|
have_gnutls = (conf.get('HAVE_GNUTLS') == 1 and libgnutls.version().version_compare('>= 3.6.0'))
|
||||||
@ -1523,12 +1527,24 @@ else
|
|||||||
endif
|
endif
|
||||||
conf.set10('ENABLE_REPART', have)
|
conf.set10('ENABLE_REPART', have)
|
||||||
|
|
||||||
|
default_dnssec = get_option('default-dnssec')
|
||||||
|
if skip_deps
|
||||||
|
default_dnssec = 'no'
|
||||||
|
endif
|
||||||
|
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.')
|
||||||
|
default_dnssec = 'no'
|
||||||
|
endif
|
||||||
|
conf.set('DEFAULT_DNSSEC_MODE',
|
||||||
|
'DNSSEC_' + default_dnssec.underscorify().to_upper())
|
||||||
|
conf.set_quoted('DEFAULT_DNSSEC_MODE_STR', default_dnssec)
|
||||||
|
|
||||||
want_importd = get_option('importd')
|
want_importd = get_option('importd')
|
||||||
if want_importd != 'false'
|
if want_importd != 'false'
|
||||||
have = (conf.get('HAVE_LIBCURL') == 1 and
|
have = (conf.get('HAVE_LIBCURL') == 1 and
|
||||||
|
conf.get('HAVE_OPENSSL_OR_GCRYPT') == 1 and
|
||||||
conf.get('HAVE_ZLIB') == 1 and
|
conf.get('HAVE_ZLIB') == 1 and
|
||||||
conf.get('HAVE_XZ') == 1 and
|
conf.get('HAVE_XZ') == 1)
|
||||||
conf.get('HAVE_GCRYPT') == 1)
|
|
||||||
if want_importd == 'true' and not have
|
if want_importd == 'true' and not have
|
||||||
error('importd support was requested, but dependencies are not available')
|
error('importd support was requested, but dependencies are not available')
|
||||||
endif
|
endif
|
||||||
@ -2139,6 +2155,7 @@ if conf.get('ENABLE_RESOLVE') == 1
|
|||||||
libbasic_gcrypt,
|
libbasic_gcrypt,
|
||||||
libsystemd_resolve_core],
|
libsystemd_resolve_core],
|
||||||
dependencies : [threads,
|
dependencies : [threads,
|
||||||
|
lib_openssl_or_gcrypt,
|
||||||
libgpg_error,
|
libgpg_error,
|
||||||
libm,
|
libm,
|
||||||
libidn],
|
libidn],
|
||||||
@ -2717,10 +2734,10 @@ if conf.get('ENABLE_IMPORTD') == 1
|
|||||||
link_with : [libshared],
|
link_with : [libshared],
|
||||||
dependencies : [versiondep,
|
dependencies : [versiondep,
|
||||||
libcurl,
|
libcurl,
|
||||||
|
lib_openssl_or_gcrypt,
|
||||||
libz,
|
libz,
|
||||||
libbzip2,
|
libbzip2,
|
||||||
libxz,
|
libxz],
|
||||||
libgcrypt],
|
|
||||||
install_rpath : rootlibexecdir,
|
install_rpath : rootlibexecdir,
|
||||||
install : true,
|
install : true,
|
||||||
install_dir : rootlibexecdir)
|
install_dir : rootlibexecdir)
|
||||||
@ -4021,6 +4038,14 @@ else
|
|||||||
found += 'static-libudev(@0@)'.format(static_libudev)
|
found += 'static-libudev(@0@)'.format(static_libudev)
|
||||||
endif
|
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
|
if conf.get('DNS_OVER_TLS_USE_GNUTLS') == 1
|
||||||
found += 'DNS-over-TLS(gnutls)'
|
found += 'DNS-over-TLS(gnutls)'
|
||||||
elif conf.get('DNS_OVER_TLS_USE_OPENSSL') == 1
|
elif conf.get('DNS_OVER_TLS_USE_OPENSSL') == 1
|
||||||
|
@ -380,6 +380,8 @@ option('gnutls', type : 'combo', choices : ['auto', 'true', 'false'],
|
|||||||
description : 'gnutls support')
|
description : 'gnutls support')
|
||||||
option('openssl', type : 'combo', choices : ['auto', 'true', 'false'],
|
option('openssl', type : 'combo', choices : ['auto', 'true', 'false'],
|
||||||
description : 'openssl support')
|
description : 'openssl support')
|
||||||
|
option('cryptolib', type : 'combo', choices : ['auto', 'openssl', 'gcrypt'],
|
||||||
|
description : 'whether to use openssl or gcrypt where both are supported')
|
||||||
option('p11kit', type : 'combo', choices : ['auto', 'true', 'false'],
|
option('p11kit', type : 'combo', choices : ['auto', 'true', 'false'],
|
||||||
description : 'p11kit support')
|
description : 'p11kit support')
|
||||||
option('libfido2', type : 'combo', choices : ['auto', 'true', 'false'],
|
option('libfido2', type : 'combo', choices : ['auto', 'true', 'false'],
|
||||||
|
@ -48,7 +48,7 @@ const char* const systemd_features =
|
|||||||
" -SECCOMP"
|
" -SECCOMP"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* crypto libraries */
|
/* cryptographic libraries */
|
||||||
|
|
||||||
#if HAVE_GCRYPT
|
#if HAVE_GCRYPT
|
||||||
" +GCRYPT"
|
" +GCRYPT"
|
||||||
|
@ -18,6 +18,7 @@ void initialize_libgcrypt(bool secmem) {
|
|||||||
gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);
|
gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# if !PREFER_OPENSSL
|
||||||
int string_hashsum(const char *s, size_t len, int md_algorithm, char **out) {
|
int string_hashsum(const char *s, size_t len, int md_algorithm, char **out) {
|
||||||
_cleanup_(gcry_md_closep) gcry_md_hd_t md = NULL;
|
_cleanup_(gcry_md_closep) gcry_md_hd_t md = NULL;
|
||||||
gcry_error_t err;
|
gcry_error_t err;
|
||||||
@ -47,4 +48,5 @@ int string_hashsum(const char *s, size_t len, int md_algorithm, char **out) {
|
|||||||
*out = enc;
|
*out = enc;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
@ -12,23 +12,28 @@
|
|||||||
#include "macro.h"
|
#include "macro.h"
|
||||||
|
|
||||||
void initialize_libgcrypt(bool secmem);
|
void initialize_libgcrypt(bool secmem);
|
||||||
int string_hashsum(const char *s, size_t len, int md_algorithm, char **out);
|
|
||||||
|
|
||||||
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(gcry_md_hd_t, gcry_md_close, NULL);
|
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(gcry_md_hd_t, gcry_md_close, NULL);
|
||||||
#endif
|
#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) {
|
static inline int string_hashsum_sha224(const char *s, size_t len, char **out) {
|
||||||
#if HAVE_GCRYPT
|
# if HAVE_GCRYPT
|
||||||
return string_hashsum(s, len, GCRY_MD_SHA224, out);
|
return string_hashsum(s, len, GCRY_MD_SHA224, out);
|
||||||
#else
|
# else
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
#endif
|
# endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int string_hashsum_sha256(const char *s, size_t len, char **out) {
|
static inline int string_hashsum_sha256(const char *s, size_t len, char **out) {
|
||||||
#if HAVE_GCRYPT
|
# if HAVE_GCRYPT
|
||||||
return string_hashsum(s, len, GCRY_MD_SHA256, out);
|
return string_hashsum(s, len, GCRY_MD_SHA256, out);
|
||||||
#else
|
# else
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
#endif
|
# endif
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
@ -41,8 +41,12 @@ PullJob* pull_job_unref(PullJob *j) {
|
|||||||
|
|
||||||
import_compress_free(&j->compress);
|
import_compress_free(&j->compress);
|
||||||
|
|
||||||
if (j->checksum_context)
|
if (j->checksum_ctx)
|
||||||
gcry_md_close(j->checksum_context);
|
#if PREFER_OPENSSL
|
||||||
|
EVP_MD_CTX_free(j->checksum_ctx);
|
||||||
|
#else
|
||||||
|
gcry_md_close(j->checksum_ctx);
|
||||||
|
#endif
|
||||||
|
|
||||||
free(j->url);
|
free(j->url);
|
||||||
free(j->etag);
|
free(j->etag);
|
||||||
@ -102,9 +106,13 @@ static int pull_job_restart(PullJob *j, const char *new_url) {
|
|||||||
|
|
||||||
import_compress_free(&j->compress);
|
import_compress_free(&j->compress);
|
||||||
|
|
||||||
if (j->checksum_context) {
|
if (j->checksum_ctx) {
|
||||||
gcry_md_close(j->checksum_context);
|
#if PREFER_OPENSSL
|
||||||
j->checksum_context = NULL;
|
EVP_MD_CTX_free(j->checksum_ctx);
|
||||||
|
#else
|
||||||
|
gcry_md_close(j->checksum_ctx);
|
||||||
|
#endif
|
||||||
|
j->checksum_ctx = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = pull_job_begin(j);
|
r = pull_job_begin(j);
|
||||||
@ -200,16 +208,30 @@ void pull_job_curl_on_finished(CurlGlue *g, CURL *curl, CURLcode result) {
|
|||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (j->checksum_context) {
|
if (j->checksum_ctx) {
|
||||||
uint8_t *k;
|
unsigned checksum_len;
|
||||||
|
#if PREFER_OPENSSL
|
||||||
|
uint8_t k[EVP_MAX_MD_SIZE];
|
||||||
|
|
||||||
k = gcry_md_read(j->checksum_context, GCRY_MD_SHA256);
|
r = EVP_DigestFinal_ex(j->checksum_ctx, k, &checksum_len);
|
||||||
|
if (r == 0) {
|
||||||
|
r = log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to get checksum.");
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
assert(checksum_len <= sizeof k);
|
||||||
|
#else
|
||||||
|
const uint8_t *k;
|
||||||
|
|
||||||
|
k = gcry_md_read(j->checksum_ctx, GCRY_MD_SHA256);
|
||||||
if (!k) {
|
if (!k) {
|
||||||
r = log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to get checksum.");
|
r = log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to get checksum.");
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
j->checksum = hexmem(k, gcry_md_get_algo_dlen(GCRY_MD_SHA256));
|
checksum_len = gcry_md_get_algo_dlen(GCRY_MD_SHA256);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
j->checksum = hexmem(k, checksum_len);
|
||||||
if (!j->checksum) {
|
if (!j->checksum) {
|
||||||
r = log_oom();
|
r = log_oom();
|
||||||
goto finish;
|
goto finish;
|
||||||
@ -358,8 +380,16 @@ static int pull_job_write_compressed(PullJob *j, void *p, size_t sz) {
|
|||||||
return log_error_errno(SYNTHETIC_ERRNO(EFBIG),
|
return log_error_errno(SYNTHETIC_ERRNO(EFBIG),
|
||||||
"Content length incorrect.");
|
"Content length incorrect.");
|
||||||
|
|
||||||
if (j->checksum_context)
|
if (j->checksum_ctx) {
|
||||||
gcry_md_write(j->checksum_context, p, sz);
|
#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);
|
r = import_uncompress(&j->compress, p, sz, pull_job_write_uncompressed, j);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
@ -392,11 +422,22 @@ static int pull_job_open_disk(PullJob *j) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (j->calc_checksum) {
|
if (j->calc_checksum) {
|
||||||
initialize_libgcrypt(false);
|
#if PREFER_OPENSSL
|
||||||
|
j->checksum_ctx = EVP_MD_CTX_new();
|
||||||
|
if (!j->checksum_ctx)
|
||||||
|
return log_oom();
|
||||||
|
|
||||||
if (gcry_md_open(&j->checksum_context, GCRY_MD_SHA256, 0) != 0)
|
r = EVP_DigestInit_ex(j->checksum_ctx, EVP_sha256(), NULL);
|
||||||
|
if (r == 0)
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(EIO),
|
return log_error_errno(SYNTHETIC_ERRNO(EIO),
|
||||||
"Failed to initialize hash context.");
|
"Failed to initialize hash context.");
|
||||||
|
#else
|
||||||
|
initialize_libgcrypt(false);
|
||||||
|
|
||||||
|
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;
|
return 0;
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <gcrypt.h>
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
#include "curl-util.h"
|
#include "curl-util.h"
|
||||||
#include "import-compress.h"
|
#include "import-compress.h"
|
||||||
#include "macro.h"
|
#include "macro.h"
|
||||||
|
#include "openssl-util.h"
|
||||||
#include "pull-common.h"
|
#include "pull-common.h"
|
||||||
|
|
||||||
typedef struct PullJob PullJob;
|
typedef struct PullJob PullJob;
|
||||||
@ -74,7 +74,7 @@ struct PullJob {
|
|||||||
usec_t last_status_usec;
|
usec_t last_status_usec;
|
||||||
|
|
||||||
bool calc_checksum;
|
bool calc_checksum;
|
||||||
gcry_md_hd_t checksum_context;
|
hash_context_t checksum_ctx;
|
||||||
|
|
||||||
char *checksum;
|
char *checksum;
|
||||||
bool sync;
|
bool sync;
|
||||||
|
@ -12,9 +12,6 @@
|
|||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
#include <openssl/hmac.h>
|
|
||||||
#include <openssl/sha.h>
|
|
||||||
|
|
||||||
#include "sd-id128.h"
|
#include "sd-id128.h"
|
||||||
|
|
||||||
#include "alloc-util.h"
|
#include "alloc-util.h"
|
||||||
@ -38,6 +35,7 @@
|
|||||||
#include "glyph-util.h"
|
#include "glyph-util.h"
|
||||||
#include "gpt.h"
|
#include "gpt.h"
|
||||||
#include "hexdecoct.h"
|
#include "hexdecoct.h"
|
||||||
|
#include "hmac.h"
|
||||||
#include "id128-util.h"
|
#include "id128-util.h"
|
||||||
#include "json.h"
|
#include "json.h"
|
||||||
#include "list.h"
|
#include "list.h"
|
||||||
@ -1519,7 +1517,7 @@ static int fdisk_set_disklabel_id_by_uuid(struct fdisk_context *c, sd_id128_t id
|
|||||||
|
|
||||||
static int derive_uuid(sd_id128_t base, const char *token, sd_id128_t *ret) {
|
static int derive_uuid(sd_id128_t base, const char *token, sd_id128_t *ret) {
|
||||||
union {
|
union {
|
||||||
unsigned char md[SHA256_DIGEST_LENGTH];
|
uint8_t md[SHA256_DIGEST_SIZE];
|
||||||
sd_id128_t id;
|
sd_id128_t id;
|
||||||
} result;
|
} result;
|
||||||
|
|
||||||
@ -1531,11 +1529,7 @@ static int derive_uuid(sd_id128_t base, const char *token, sd_id128_t *ret) {
|
|||||||
* machine ID). We use the machine ID as key (and not as cleartext!) of the HMAC operation since it's
|
* machine ID). We use the machine ID as key (and not as cleartext!) of the HMAC operation since it's
|
||||||
* the machine ID we don't want to leak. */
|
* the machine ID we don't want to leak. */
|
||||||
|
|
||||||
if (!HMAC(EVP_sha256(),
|
hmac_sha256(base.bytes, sizeof(base.bytes), token, strlen(token), result.md);
|
||||||
&base, sizeof(base),
|
|
||||||
(const unsigned char*) token, strlen(token),
|
|
||||||
result.md, NULL))
|
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "HMAC-SHA256 calculation failed.");
|
|
||||||
|
|
||||||
/* Take the first half, mark it as v4 UUID */
|
/* Take the first half, mark it as v4 UUID */
|
||||||
assert_cc(sizeof(result.md) == sizeof(result.id) * 2);
|
assert_cc(sizeof(result.md) == sizeof(result.id) * 2);
|
||||||
@ -3067,7 +3061,7 @@ static int partition_acquire_uuid(Context *context, Partition *p, sd_id128_t *re
|
|||||||
uint64_t counter;
|
uint64_t counter;
|
||||||
} _packed_ plaintext = {};
|
} _packed_ plaintext = {};
|
||||||
union {
|
union {
|
||||||
unsigned char md[SHA256_DIGEST_LENGTH];
|
uint8_t md[SHA256_DIGEST_SIZE];
|
||||||
sd_id128_t id;
|
sd_id128_t id;
|
||||||
} result;
|
} result;
|
||||||
|
|
||||||
@ -3111,11 +3105,10 @@ static int partition_acquire_uuid(Context *context, Partition *p, sd_id128_t *re
|
|||||||
plaintext.type_uuid = p->type_uuid;
|
plaintext.type_uuid = p->type_uuid;
|
||||||
plaintext.counter = htole64(k);
|
plaintext.counter = htole64(k);
|
||||||
|
|
||||||
if (!HMAC(EVP_sha256(),
|
hmac_sha256(context->seed.bytes, sizeof(context->seed.bytes),
|
||||||
&context->seed, sizeof(context->seed),
|
&plaintext,
|
||||||
(const unsigned char*) &plaintext, k == 0 ? sizeof(sd_id128_t) : sizeof(plaintext),
|
k == 0 ? sizeof(sd_id128_t) : sizeof(plaintext),
|
||||||
result.md, NULL))
|
result.md);
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "SHA256 calculation failed.");
|
|
||||||
|
|
||||||
/* Take the first half, mark it as v4 UUID */
|
/* Take the first half, mark it as v4 UUID */
|
||||||
assert_cc(sizeof(result.md) == sizeof(result.id) * 2);
|
assert_cc(sizeof(result.md) == sizeof(result.id) * 2);
|
||||||
|
@ -176,14 +176,16 @@ tests += [
|
|||||||
[['src/resolve/test-resolve-tables.c'],
|
[['src/resolve/test-resolve-tables.c'],
|
||||||
[libsystemd_resolve_core,
|
[libsystemd_resolve_core,
|
||||||
libshared],
|
libshared],
|
||||||
[libgcrypt,
|
[lib_openssl_or_gcrypt,
|
||||||
|
libgcrypt,
|
||||||
libgpg_error,
|
libgpg_error,
|
||||||
libm]],
|
libm]],
|
||||||
|
|
||||||
[['src/resolve/test-dns-packet.c'],
|
[['src/resolve/test-dns-packet.c'],
|
||||||
[libsystemd_resolve_core,
|
[libsystemd_resolve_core,
|
||||||
libshared],
|
libshared],
|
||||||
[libgcrypt,
|
[lib_openssl_or_gcrypt,
|
||||||
|
libgcrypt,
|
||||||
libgpg_error,
|
libgpg_error,
|
||||||
libm]],
|
libm]],
|
||||||
|
|
||||||
@ -192,28 +194,33 @@ tests += [
|
|||||||
'src/resolve/resolved-etc-hosts.h'],
|
'src/resolve/resolved-etc-hosts.h'],
|
||||||
[libsystemd_resolve_core,
|
[libsystemd_resolve_core,
|
||||||
libshared],
|
libshared],
|
||||||
[libgcrypt,
|
[lib_openssl_or_gcrypt,
|
||||||
|
libgcrypt,
|
||||||
libgpg_error,
|
libgpg_error,
|
||||||
libm]],
|
libm]],
|
||||||
|
|
||||||
[['src/resolve/test-resolved-packet.c'],
|
[['src/resolve/test-resolved-packet.c'],
|
||||||
[libsystemd_resolve_core,
|
[libsystemd_resolve_core,
|
||||||
libshared],
|
libshared],
|
||||||
[libgcrypt,
|
[lib_openssl_or_gcrypt,
|
||||||
|
libgcrypt,
|
||||||
libgpg_error,
|
libgpg_error,
|
||||||
libm]],
|
libm]],
|
||||||
|
|
||||||
[['src/resolve/test-dnssec.c'],
|
[['src/resolve/test-dnssec.c'],
|
||||||
[libsystemd_resolve_core,
|
[libsystemd_resolve_core,
|
||||||
libshared],
|
libshared],
|
||||||
[libgcrypt,
|
[lib_openssl_or_gcrypt,
|
||||||
|
libgcrypt,
|
||||||
libgpg_error,
|
libgpg_error,
|
||||||
libm]],
|
libm],
|
||||||
|
[], 'HAVE_OPENSSL_OR_GCRYPT'],
|
||||||
|
|
||||||
[['src/resolve/test-dnssec-complex.c'],
|
[['src/resolve/test-dnssec-complex.c'],
|
||||||
[libsystemd_resolve_core,
|
[libsystemd_resolve_core,
|
||||||
libshared],
|
libshared],
|
||||||
[libgcrypt,
|
[lib_openssl_or_gcrypt,
|
||||||
|
libgcrypt,
|
||||||
libgpg_error,
|
libgpg_error,
|
||||||
libm],
|
libm],
|
||||||
[], '', 'manual'],
|
[], '', 'manual'],
|
||||||
@ -223,7 +230,8 @@ fuzzers += [
|
|||||||
[['src/resolve/fuzz-dns-packet.c'],
|
[['src/resolve/fuzz-dns-packet.c'],
|
||||||
[libsystemd_resolve_core,
|
[libsystemd_resolve_core,
|
||||||
libshared],
|
libshared],
|
||||||
[libgcrypt,
|
[lib_openssl_or_gcrypt,
|
||||||
|
libgcrypt,
|
||||||
libgpg_error,
|
libgpg_error,
|
||||||
libm]],
|
libm]],
|
||||||
]
|
]
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#include "main-func.h"
|
#include "main-func.h"
|
||||||
#include "missing_network.h"
|
#include "missing_network.h"
|
||||||
#include "netlink-util.h"
|
#include "netlink-util.h"
|
||||||
|
#include "openssl-util.h"
|
||||||
#include "pager.h"
|
#include "pager.h"
|
||||||
#include "parse-argument.h"
|
#include "parse-argument.h"
|
||||||
#include "parse-util.h"
|
#include "parse-util.h"
|
||||||
|
@ -498,14 +498,14 @@ int manager_parse_config_file(Manager *m) {
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ! HAVE_GCRYPT
|
#if !HAVE_OPENSSL_OR_GCRYPT
|
||||||
if (m->dnssec_mode != DNSSEC_NO) {
|
if (m->dnssec_mode != DNSSEC_NO) {
|
||||||
log_warning("DNSSEC option cannot be enabled or set to allow-downgrade when systemd-resolved is built without gcrypt support. Turning off DNSSEC support.");
|
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.");
|
||||||
m->dnssec_mode = DNSSEC_NO;
|
m->dnssec_mode = DNSSEC_NO;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if ! ENABLE_DNS_OVER_TLS
|
#if !ENABLE_DNS_OVER_TLS
|
||||||
if (m->dns_over_tls_mode != DNS_OVER_TLS_NO) {
|
if (m->dns_over_tls_mode != DNS_OVER_TLS_NO) {
|
||||||
log_warning("DNS-over-TLS option cannot be enabled or set to opportunistic when systemd-resolved is built without DNS-over-TLS support. Turning off DNS-over-TLS support.");
|
log_warning("DNS-over-TLS option cannot be enabled or set to opportunistic when systemd-resolved is built without DNS-over-TLS support. Turning off DNS-over-TLS support.");
|
||||||
m->dns_over_tls_mode = DNS_OVER_TLS_NO;
|
m->dns_over_tls_mode = DNS_OVER_TLS_NO;
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include "gcrypt-util.h"
|
#include "gcrypt-util.h"
|
||||||
#include "hexdecoct.h"
|
#include "hexdecoct.h"
|
||||||
#include "memory-util.h"
|
#include "memory-util.h"
|
||||||
|
#include "openssl-util.h"
|
||||||
#include "resolved-dns-dnssec.h"
|
#include "resolved-dns-dnssec.h"
|
||||||
#include "resolved-dns-packet.h"
|
#include "resolved-dns-packet.h"
|
||||||
#include "sort-util.h"
|
#include "sort-util.h"
|
||||||
@ -58,7 +59,7 @@ uint16_t dnssec_keytag(DnsResourceRecord *dnskey, bool mask_revoke) {
|
|||||||
return sum & UINT32_C(0xFFFF);
|
return sum & UINT32_C(0xFFFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if HAVE_GCRYPT
|
#if HAVE_OPENSSL_OR_GCRYPT
|
||||||
|
|
||||||
static int rr_compare(DnsResourceRecord * const *a, DnsResourceRecord * const *b) {
|
static int rr_compare(DnsResourceRecord * const *a, DnsResourceRecord * const *b) {
|
||||||
const DnsResourceRecord *x = *a, *y = *b;
|
const DnsResourceRecord *x = *a, *y = *b;
|
||||||
@ -82,12 +83,67 @@ static int rr_compare(DnsResourceRecord * const *a, DnsResourceRecord * const *b
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int dnssec_rsa_verify_raw(
|
static int dnssec_rsa_verify_raw(
|
||||||
const char *hash_algorithm,
|
hash_algorithm_t hash_algorithm,
|
||||||
const void *signature, size_t signature_size,
|
const void *signature, size_t signature_size,
|
||||||
const void *data, size_t data_size,
|
const void *data, size_t data_size,
|
||||||
const void *exponent, size_t exponent_size,
|
const void *exponent, size_t exponent_size,
|
||||||
const void *modulus, size_t modulus_size) {
|
const void *modulus, size_t modulus_size) {
|
||||||
|
|
||||||
|
#if PREFER_OPENSSL
|
||||||
|
_cleanup_(RSA_freep) RSA *rpubkey = NULL;
|
||||||
|
_cleanup_(EVP_PKEY_freep) EVP_PKEY *epubkey = NULL;
|
||||||
|
_cleanup_(EVP_PKEY_CTX_freep) EVP_PKEY_CTX *ctx = NULL;
|
||||||
|
_cleanup_(BN_freep) BIGNUM *e = NULL, *m = NULL;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(hash_algorithm);
|
||||||
|
|
||||||
|
e = BN_bin2bn(exponent, exponent_size, NULL);
|
||||||
|
if (!e)
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
m = BN_bin2bn(modulus, modulus_size, NULL);
|
||||||
|
if (!m)
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
rpubkey = RSA_new();
|
||||||
|
if (!rpubkey)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
if (RSA_set0_key(rpubkey, m, e, NULL) <= 0)
|
||||||
|
return -EIO;
|
||||||
|
e = m = NULL;
|
||||||
|
|
||||||
|
assert((size_t) RSA_size(rpubkey) == signature_size);
|
||||||
|
|
||||||
|
epubkey = EVP_PKEY_new();
|
||||||
|
if (!epubkey)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
if (EVP_PKEY_assign_RSA(epubkey, RSAPublicKey_dup(rpubkey)) <= 0)
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
ctx = EVP_PKEY_CTX_new(epubkey, NULL);
|
||||||
|
if (!ctx)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
if (EVP_PKEY_verify_init(ctx) <= 0)
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0)
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
if (EVP_PKEY_CTX_set_signature_md(ctx, hash_algorithm) <= 0)
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
r = EVP_PKEY_verify(ctx, signature, signature_size, data, data_size);
|
||||||
|
if (r < 0)
|
||||||
|
return log_debug_errno(SYNTHETIC_ERRNO(EIO),
|
||||||
|
"Signature verification failed: 0x%lx", ERR_get_error());
|
||||||
|
|
||||||
|
return r;
|
||||||
|
|
||||||
|
#else
|
||||||
gcry_sexp_t public_key_sexp = NULL, data_sexp = NULL, signature_sexp = NULL;
|
gcry_sexp_t public_key_sexp = NULL, data_sexp = NULL, signature_sexp = NULL;
|
||||||
gcry_mpi_t n = NULL, e = NULL, s = NULL;
|
gcry_mpi_t n = NULL, e = NULL, s = NULL;
|
||||||
gcry_error_t ge;
|
gcry_error_t ge;
|
||||||
@ -147,10 +203,10 @@ static int dnssec_rsa_verify_raw(
|
|||||||
ge = gcry_pk_verify(signature_sexp, data_sexp, public_key_sexp);
|
ge = gcry_pk_verify(signature_sexp, data_sexp, public_key_sexp);
|
||||||
if (gpg_err_code(ge) == GPG_ERR_BAD_SIGNATURE)
|
if (gpg_err_code(ge) == GPG_ERR_BAD_SIGNATURE)
|
||||||
r = 0;
|
r = 0;
|
||||||
else if (ge != 0) {
|
else if (ge != 0)
|
||||||
log_debug("RSA signature check failed: %s", gpg_strerror(ge));
|
r = log_debug_errno(SYNTHETIC_ERRNO(EIO),
|
||||||
r = -EIO;
|
"RSA signature check failed: %s", gpg_strerror(ge));
|
||||||
} else
|
else
|
||||||
r = 1;
|
r = 1;
|
||||||
|
|
||||||
finish:
|
finish:
|
||||||
@ -169,10 +225,11 @@ finish:
|
|||||||
gcry_sexp_release(data_sexp);
|
gcry_sexp_release(data_sexp);
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dnssec_rsa_verify(
|
static int dnssec_rsa_verify(
|
||||||
const char *hash_algorithm,
|
hash_algorithm_t hash_algorithm,
|
||||||
const void *hash, size_t hash_size,
|
const void *hash, size_t hash_size,
|
||||||
DnsResourceRecord *rrsig,
|
DnsResourceRecord *rrsig,
|
||||||
DnsResourceRecord *dnskey) {
|
DnsResourceRecord *dnskey) {
|
||||||
@ -228,13 +285,78 @@ static int dnssec_rsa_verify(
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int dnssec_ecdsa_verify_raw(
|
static int dnssec_ecdsa_verify_raw(
|
||||||
const char *hash_algorithm,
|
hash_algorithm_t hash_algorithm,
|
||||||
const char *curve,
|
elliptic_curve_t curve,
|
||||||
const void *signature_r, size_t signature_r_size,
|
const void *signature_r, size_t signature_r_size,
|
||||||
const void *signature_s, size_t signature_s_size,
|
const void *signature_s, size_t signature_s_size,
|
||||||
const void *data, size_t data_size,
|
const void *data, size_t data_size,
|
||||||
const void *key, size_t key_size) {
|
const void *key, size_t key_size) {
|
||||||
|
|
||||||
|
#if PREFER_OPENSSL
|
||||||
|
_cleanup_(EC_GROUP_freep) EC_GROUP *ec_group = NULL;
|
||||||
|
_cleanup_(EC_POINT_freep) EC_POINT *p = NULL;
|
||||||
|
_cleanup_(EC_KEY_freep) EC_KEY *eckey = NULL;
|
||||||
|
_cleanup_(BN_CTX_freep) BN_CTX *bctx = NULL;
|
||||||
|
_cleanup_(BN_freep) BIGNUM *r = NULL, *s = NULL;
|
||||||
|
_cleanup_(ECDSA_SIG_freep) ECDSA_SIG *sig = NULL;
|
||||||
|
int k;
|
||||||
|
|
||||||
|
assert(hash_algorithm);
|
||||||
|
|
||||||
|
ec_group = EC_GROUP_new_by_curve_name(curve);
|
||||||
|
if (!ec_group)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
p = EC_POINT_new(ec_group);
|
||||||
|
if (!p)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
bctx = BN_CTX_new();
|
||||||
|
if (!bctx)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
if (EC_POINT_oct2point(ec_group, p, key, key_size, bctx) <= 0)
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
eckey = EC_KEY_new();
|
||||||
|
if (!eckey)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
if (EC_KEY_set_group(eckey, ec_group) <= 0)
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
if (EC_KEY_set_public_key(eckey, p) <= 0)
|
||||||
|
return log_debug_errno(SYNTHETIC_ERRNO(EIO),
|
||||||
|
"EC_POINT_bn2point failed: 0x%lx", ERR_get_error());
|
||||||
|
|
||||||
|
assert(EC_KEY_check_key(eckey) == 1);
|
||||||
|
|
||||||
|
r = BN_bin2bn(signature_r, signature_r_size, NULL);
|
||||||
|
if (!r)
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
s = BN_bin2bn(signature_s, signature_s_size, NULL);
|
||||||
|
if (!s)
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
/* TODO: We should eventually use use the EVP API once it supports ECDSA signature verification */
|
||||||
|
|
||||||
|
sig = ECDSA_SIG_new();
|
||||||
|
if (!sig)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
if (ECDSA_SIG_set0(sig, r, s) <= 0)
|
||||||
|
return -EIO;
|
||||||
|
r = s = NULL;
|
||||||
|
|
||||||
|
k = ECDSA_do_verify(data, data_size, sig, eckey);
|
||||||
|
if (k < 0)
|
||||||
|
return log_debug_errno(SYNTHETIC_ERRNO(EIO),
|
||||||
|
"Signature verification failed: 0x%lx", ERR_get_error());
|
||||||
|
|
||||||
|
return k;
|
||||||
|
|
||||||
|
#else
|
||||||
gcry_sexp_t public_key_sexp = NULL, data_sexp = NULL, signature_sexp = NULL;
|
gcry_sexp_t public_key_sexp = NULL, data_sexp = NULL, signature_sexp = NULL;
|
||||||
gcry_mpi_t q = NULL, r = NULL, s = NULL;
|
gcry_mpi_t q = NULL, r = NULL, s = NULL;
|
||||||
gcry_error_t ge;
|
gcry_error_t ge;
|
||||||
@ -315,16 +437,17 @@ finish:
|
|||||||
gcry_sexp_release(data_sexp);
|
gcry_sexp_release(data_sexp);
|
||||||
|
|
||||||
return k;
|
return k;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dnssec_ecdsa_verify(
|
static int dnssec_ecdsa_verify(
|
||||||
const char *hash_algorithm,
|
hash_algorithm_t hash_algorithm,
|
||||||
int algorithm,
|
int algorithm,
|
||||||
const void *hash, size_t hash_size,
|
const void *hash, size_t hash_size,
|
||||||
DnsResourceRecord *rrsig,
|
DnsResourceRecord *rrsig,
|
||||||
DnsResourceRecord *dnskey) {
|
DnsResourceRecord *dnskey) {
|
||||||
|
|
||||||
const char *curve;
|
elliptic_curve_t curve;
|
||||||
size_t key_size;
|
size_t key_size;
|
||||||
uint8_t *q;
|
uint8_t *q;
|
||||||
|
|
||||||
@ -334,11 +457,11 @@ static int dnssec_ecdsa_verify(
|
|||||||
assert(dnskey);
|
assert(dnskey);
|
||||||
|
|
||||||
if (algorithm == DNSSEC_ALGORITHM_ECDSAP256SHA256) {
|
if (algorithm == DNSSEC_ALGORITHM_ECDSAP256SHA256) {
|
||||||
|
curve = OPENSSL_OR_GCRYPT(NID_X9_62_prime256v1, "NIST P-256"); /* NIST P-256 */
|
||||||
key_size = 32;
|
key_size = 32;
|
||||||
curve = "NIST P-256";
|
|
||||||
} else if (algorithm == DNSSEC_ALGORITHM_ECDSAP384SHA384) {
|
} else if (algorithm == DNSSEC_ALGORITHM_ECDSAP384SHA384) {
|
||||||
|
curve = OPENSSL_OR_GCRYPT(NID_secp384r1, "NIST P-384"); /* NIST P-384 */
|
||||||
key_size = 48;
|
key_size = 48;
|
||||||
curve = "NIST P-384";
|
|
||||||
} else
|
} else
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
@ -361,25 +484,66 @@ static int dnssec_ecdsa_verify(
|
|||||||
q, key_size*2+1);
|
q, key_size*2+1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if GCRYPT_VERSION_NUMBER >= 0x010600
|
|
||||||
static int dnssec_eddsa_verify_raw(
|
static int dnssec_eddsa_verify_raw(
|
||||||
const char *curve,
|
elliptic_curve_t curve,
|
||||||
const void *signature_r, size_t signature_r_size,
|
const uint8_t *signature, size_t signature_size,
|
||||||
const void *signature_s, size_t signature_s_size,
|
const uint8_t *data, size_t data_size,
|
||||||
const void *data, size_t data_size,
|
const uint8_t *key, size_t key_size) {
|
||||||
const void *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;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(curve == NID_ED25519);
|
||||||
|
assert(signature_size == key_size * 2);
|
||||||
|
|
||||||
|
uint8_t *q = newa(uint8_t, signature_size + 1);
|
||||||
|
q[0] = 0x04; /* Prepend 0x04 to indicate an uncompressed key */
|
||||||
|
memcpy(q+1, signature, signature_size);
|
||||||
|
|
||||||
|
evkey = EVP_PKEY_new_raw_public_key(EVP_PKEY_ED25519, NULL, key, key_size);
|
||||||
|
if (!evkey)
|
||||||
|
return log_debug_errno(SYNTHETIC_ERRNO(EIO),
|
||||||
|
"EVP_PKEY_new_raw_public_key failed: 0x%lx", ERR_get_error());
|
||||||
|
|
||||||
|
pctx = EVP_PKEY_CTX_new(evkey, NULL);
|
||||||
|
if (!pctx)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
ctx = EVP_MD_CTX_new();
|
||||||
|
if (!ctx)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
/* This prevents EVP_DigestVerifyInit from managing pctx and complicating our free logic. */
|
||||||
|
EVP_MD_CTX_set_pkey_ctx(ctx, pctx);
|
||||||
|
|
||||||
|
/* One might be tempted to use EVP_PKEY_verify_init, but see Ed25519(7ssl). */
|
||||||
|
if (EVP_DigestVerifyInit(ctx, &pctx, NULL, NULL, evkey) <= 0)
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
r = EVP_DigestVerify(ctx, signature, signature_size, data, data_size);
|
||||||
|
if (r < 0)
|
||||||
|
return log_debug_errno(SYNTHETIC_ERRNO(EIO),
|
||||||
|
"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_sexp_t public_key_sexp = NULL, data_sexp = NULL, signature_sexp = NULL;
|
||||||
gcry_error_t ge;
|
gcry_error_t ge;
|
||||||
int k;
|
int k;
|
||||||
|
|
||||||
|
assert(signature_size == key_size * 2);
|
||||||
|
|
||||||
ge = gcry_sexp_build(&signature_sexp,
|
ge = gcry_sexp_build(&signature_sexp,
|
||||||
NULL,
|
NULL,
|
||||||
"(sig-val (eddsa (r %b) (s %b)))",
|
"(sig-val (eddsa (r %b) (s %b)))",
|
||||||
(int) signature_r_size,
|
(int) key_size,
|
||||||
signature_r,
|
signature,
|
||||||
(int) signature_s_size,
|
(int) key_size,
|
||||||
signature_s);
|
signature + key_size);
|
||||||
if (ge != 0) {
|
if (ge != 0) {
|
||||||
k = -EIO;
|
k = -EIO;
|
||||||
goto finish;
|
goto finish;
|
||||||
@ -409,10 +573,10 @@ static int dnssec_eddsa_verify_raw(
|
|||||||
ge = gcry_pk_verify(signature_sexp, data_sexp, public_key_sexp);
|
ge = gcry_pk_verify(signature_sexp, data_sexp, public_key_sexp);
|
||||||
if (gpg_err_code(ge) == GPG_ERR_BAD_SIGNATURE)
|
if (gpg_err_code(ge) == GPG_ERR_BAD_SIGNATURE)
|
||||||
k = 0;
|
k = 0;
|
||||||
else if (ge != 0) {
|
else if (ge != 0)
|
||||||
log_debug("EdDSA signature check failed: %s", gpg_strerror(ge));
|
k = log_debug_errno(SYNTHETIC_ERRNO(EIO),
|
||||||
k = -EIO;
|
"EdDSA signature check failed: %s", gpg_strerror(ge));
|
||||||
} else
|
else
|
||||||
k = 1;
|
k = 1;
|
||||||
finish:
|
finish:
|
||||||
if (public_key_sexp)
|
if (public_key_sexp)
|
||||||
@ -423,6 +587,9 @@ finish:
|
|||||||
gcry_sexp_release(data_sexp);
|
gcry_sexp_release(data_sexp);
|
||||||
|
|
||||||
return k;
|
return k;
|
||||||
|
#else
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dnssec_eddsa_verify(
|
static int dnssec_eddsa_verify(
|
||||||
@ -430,11 +597,11 @@ static int dnssec_eddsa_verify(
|
|||||||
const void *data, size_t data_size,
|
const void *data, size_t data_size,
|
||||||
DnsResourceRecord *rrsig,
|
DnsResourceRecord *rrsig,
|
||||||
DnsResourceRecord *dnskey) {
|
DnsResourceRecord *dnskey) {
|
||||||
const char *curve;
|
elliptic_curve_t curve;
|
||||||
size_t key_size;
|
size_t key_size;
|
||||||
|
|
||||||
if (algorithm == DNSSEC_ALGORITHM_ED25519) {
|
if (algorithm == DNSSEC_ALGORITHM_ED25519) {
|
||||||
curve = "Ed25519";
|
curve = OPENSSL_OR_GCRYPT(NID_ED25519, "Ed25519");
|
||||||
key_size = 32;
|
key_size = 32;
|
||||||
} else
|
} else
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
@ -447,20 +614,28 @@ static int dnssec_eddsa_verify(
|
|||||||
|
|
||||||
return dnssec_eddsa_verify_raw(
|
return dnssec_eddsa_verify_raw(
|
||||||
curve,
|
curve,
|
||||||
rrsig->rrsig.signature, key_size,
|
rrsig->rrsig.signature, rrsig->rrsig.signature_size,
|
||||||
(uint8_t*) rrsig->rrsig.signature + key_size, key_size,
|
|
||||||
data, data_size,
|
data, data_size,
|
||||||
dnskey->dnskey.key, key_size);
|
dnskey->dnskey.key, key_size);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
static void md_add_uint8(gcry_md_hd_t md, uint8_t v) {
|
static int md_add_uint8(hash_context_t ctx, uint8_t v) {
|
||||||
gcry_md_write(md, &v, sizeof(v));
|
#if PREFER_OPENSSL
|
||||||
|
return EVP_DigestUpdate(ctx, &v, sizeof(v));
|
||||||
|
#else
|
||||||
|
gcry_md_write(ctx, &v, sizeof(v));
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void md_add_uint16(gcry_md_hd_t md, uint16_t v) {
|
static int md_add_uint16(hash_context_t ctx, uint16_t v) {
|
||||||
v = htobe16(v);
|
v = htobe16(v);
|
||||||
gcry_md_write(md, &v, sizeof(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) {
|
static void fwrite_uint8(FILE *fp, uint8_t v) {
|
||||||
@ -565,36 +740,32 @@ static int dnssec_rrsig_expired(DnsResourceRecord *rrsig, usec_t realtime) {
|
|||||||
return realtime < inception || realtime > expiration;
|
return realtime < inception || realtime > expiration;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int algorithm_to_gcrypt_md(uint8_t algorithm) {
|
static hash_md_t algorithm_to_implementation_id(uint8_t algorithm) {
|
||||||
|
|
||||||
/* Translates a DNSSEC signature algorithm into a gcrypt
|
/* Translates a DNSSEC signature algorithm into an openssl/gcrypt digest identifier.
|
||||||
* digest identifier.
|
|
||||||
*
|
*
|
||||||
* Note that we implement all algorithms listed as "Must
|
* Note that we implement all algorithms listed as "Must implement" and "Recommended to Implement" in
|
||||||
* implement" and "Recommended to Implement" in RFC6944. We
|
* RFC6944. We don't implement any algorithms that are listed as "Optional" or "Must Not Implement".
|
||||||
* don't implement any algorithms that are listed as
|
* Specifically, we do not implement RSAMD5, DSASHA1, DH, DSA-NSEC3-SHA1, and GOST-ECC. */
|
||||||
* "Optional" or "Must Not Implement". Specifically, we do not
|
|
||||||
* implement RSAMD5, DSASHA1, DH, DSA-NSEC3-SHA1, and
|
|
||||||
* GOST-ECC. */
|
|
||||||
|
|
||||||
switch (algorithm) {
|
switch (algorithm) {
|
||||||
|
|
||||||
case DNSSEC_ALGORITHM_RSASHA1:
|
case DNSSEC_ALGORITHM_RSASHA1:
|
||||||
case DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1:
|
case DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1:
|
||||||
return GCRY_MD_SHA1;
|
return OPENSSL_OR_GCRYPT(EVP_sha1(), GCRY_MD_SHA1);
|
||||||
|
|
||||||
case DNSSEC_ALGORITHM_RSASHA256:
|
case DNSSEC_ALGORITHM_RSASHA256:
|
||||||
case DNSSEC_ALGORITHM_ECDSAP256SHA256:
|
case DNSSEC_ALGORITHM_ECDSAP256SHA256:
|
||||||
return GCRY_MD_SHA256;
|
return OPENSSL_OR_GCRYPT(EVP_sha256(), GCRY_MD_SHA256);
|
||||||
|
|
||||||
case DNSSEC_ALGORITHM_ECDSAP384SHA384:
|
case DNSSEC_ALGORITHM_ECDSAP384SHA384:
|
||||||
return GCRY_MD_SHA384;
|
return OPENSSL_OR_GCRYPT(EVP_sha384(), GCRY_MD_SHA384);
|
||||||
|
|
||||||
case DNSSEC_ALGORITHM_RSASHA512:
|
case DNSSEC_ALGORITHM_RSASHA512:
|
||||||
return GCRY_MD_SHA512;
|
return OPENSSL_OR_GCRYPT(EVP_sha512(), GCRY_MD_SHA512);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return -EOPNOTSUPP;
|
return OPENSSL_OR_GCRYPT(NULL, -EOPNOTSUPP);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -625,6 +796,183 @@ static void dnssec_fix_rrset_ttl(
|
|||||||
rrsig->expiry = rrsig->rrsig.expiration * USEC_PER_SEC;
|
rrsig->expiry = rrsig->rrsig.expiration * USEC_PER_SEC;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int dnssec_rrset_serialize_sig(
|
||||||
|
DnsResourceRecord *rrsig,
|
||||||
|
const char *source,
|
||||||
|
DnsResourceRecord **list,
|
||||||
|
size_t list_len,
|
||||||
|
bool wildcard,
|
||||||
|
char **ret_sig_data,
|
||||||
|
size_t *ret_sig_size) {
|
||||||
|
|
||||||
|
_cleanup_free_ char *sig_data = NULL;
|
||||||
|
size_t sig_size = 0;
|
||||||
|
_cleanup_fclose_ FILE *f = NULL;
|
||||||
|
uint8_t wire_format_name[DNS_WIRE_FORMAT_HOSTNAME_MAX];
|
||||||
|
DnsResourceRecord *rr;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(rrsig);
|
||||||
|
assert(source);
|
||||||
|
assert(list || list_len == 0);
|
||||||
|
assert(ret_sig_data);
|
||||||
|
assert(ret_sig_size);
|
||||||
|
|
||||||
|
f = open_memstream_unlocked(&sig_data, &sig_size);
|
||||||
|
if (!f)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
fwrite_uint16(f, rrsig->rrsig.type_covered);
|
||||||
|
fwrite_uint8(f, rrsig->rrsig.algorithm);
|
||||||
|
fwrite_uint8(f, rrsig->rrsig.labels);
|
||||||
|
fwrite_uint32(f, rrsig->rrsig.original_ttl);
|
||||||
|
fwrite_uint32(f, rrsig->rrsig.expiration);
|
||||||
|
fwrite_uint32(f, rrsig->rrsig.inception);
|
||||||
|
fwrite_uint16(f, rrsig->rrsig.key_tag);
|
||||||
|
|
||||||
|
r = dns_name_to_wire_format(rrsig->rrsig.signer, wire_format_name, sizeof(wire_format_name), true);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
fwrite(wire_format_name, 1, r, f);
|
||||||
|
|
||||||
|
/* Convert the source of synthesis into wire format */
|
||||||
|
r = dns_name_to_wire_format(source, wire_format_name, sizeof(wire_format_name), true);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
for (size_t k = 0; k < list_len; k++) {
|
||||||
|
size_t l;
|
||||||
|
|
||||||
|
rr = list[k];
|
||||||
|
|
||||||
|
/* Hash the source of synthesis. If this is a wildcard, then prefix it with the *. label */
|
||||||
|
if (wildcard)
|
||||||
|
fwrite((uint8_t[]) { 1, '*'}, sizeof(uint8_t), 2, f);
|
||||||
|
fwrite(wire_format_name, 1, r, f);
|
||||||
|
|
||||||
|
fwrite_uint16(f, rr->key->type);
|
||||||
|
fwrite_uint16(f, rr->key->class);
|
||||||
|
fwrite_uint32(f, rrsig->rrsig.original_ttl);
|
||||||
|
|
||||||
|
l = DNS_RESOURCE_RECORD_RDATA_SIZE(rr);
|
||||||
|
assert(l <= 0xFFFF);
|
||||||
|
|
||||||
|
fwrite_uint16(f, (uint16_t) l);
|
||||||
|
fwrite(DNS_RESOURCE_RECORD_RDATA(rr), 1, l, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
r = fflush_and_check(f);
|
||||||
|
f = safe_fclose(f); /* sig_data may be reallocated when f is closed. */
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
*ret_sig_data = TAKE_PTR(sig_data);
|
||||||
|
*ret_sig_size = sig_size;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dnssec_rrset_verify_sig(
|
||||||
|
DnsResourceRecord *rrsig,
|
||||||
|
DnsResourceRecord *dnskey,
|
||||||
|
const char *sig_data,
|
||||||
|
size_t sig_size) {
|
||||||
|
|
||||||
|
assert(rrsig);
|
||||||
|
assert(dnskey);
|
||||||
|
assert(sig_data);
|
||||||
|
assert(sig_size > 0);
|
||||||
|
|
||||||
|
hash_md_t 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;
|
||||||
|
|
||||||
|
initialize_libgcrypt(false);
|
||||||
|
#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;
|
||||||
|
|
||||||
|
_cleanup_(EVP_MD_CTX_freep) EVP_MD_CTX *ctx = EVP_MD_CTX_new();
|
||||||
|
if (!ctx)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
if (EVP_DigestInit_ex(ctx, md_algorithm, NULL) <= 0)
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
if (EVP_DigestUpdate(ctx, sig_data, sig_size) <= 0)
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
if (EVP_DigestFinal_ex(ctx, hash, &hash_size) <= 0)
|
||||||
|
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) {
|
||||||
|
|
||||||
|
case DNSSEC_ALGORITHM_RSASHA1:
|
||||||
|
case DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1:
|
||||||
|
case DNSSEC_ALGORITHM_RSASHA256:
|
||||||
|
case DNSSEC_ALGORITHM_RSASHA512:
|
||||||
|
return dnssec_rsa_verify(
|
||||||
|
OPENSSL_OR_GCRYPT(md_algorithm, gcry_md_algo_name(md_algorithm)),
|
||||||
|
hash, hash_size,
|
||||||
|
rrsig,
|
||||||
|
dnskey);
|
||||||
|
|
||||||
|
case DNSSEC_ALGORITHM_ECDSAP256SHA256:
|
||||||
|
case DNSSEC_ALGORITHM_ECDSAP384SHA384:
|
||||||
|
return dnssec_ecdsa_verify(
|
||||||
|
OPENSSL_OR_GCRYPT(md_algorithm, gcry_md_algo_name(md_algorithm)),
|
||||||
|
rrsig->rrsig.algorithm,
|
||||||
|
hash, hash_size,
|
||||||
|
rrsig,
|
||||||
|
dnskey);
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert_not_reached();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int dnssec_verify_rrset(
|
int dnssec_verify_rrset(
|
||||||
DnsAnswer *a,
|
DnsAnswer *a,
|
||||||
const DnsResourceKey *key,
|
const DnsResourceKey *key,
|
||||||
@ -633,18 +981,12 @@ int dnssec_verify_rrset(
|
|||||||
usec_t realtime,
|
usec_t realtime,
|
||||||
DnssecResult *result) {
|
DnssecResult *result) {
|
||||||
|
|
||||||
uint8_t wire_format_name[DNS_WIRE_FORMAT_HOSTNAME_MAX];
|
|
||||||
DnsResourceRecord **list, *rr;
|
DnsResourceRecord **list, *rr;
|
||||||
const char *source, *name;
|
const char *source, *name;
|
||||||
_cleanup_(gcry_md_closep) gcry_md_hd_t md = NULL;
|
size_t n = 0, sig_size;
|
||||||
int r, md_algorithm;
|
|
||||||
size_t n = 0;
|
|
||||||
size_t sig_size = 0;
|
|
||||||
_cleanup_free_ char *sig_data = NULL;
|
_cleanup_free_ char *sig_data = NULL;
|
||||||
_cleanup_fclose_ FILE *f = NULL;
|
|
||||||
size_t hash_size;
|
|
||||||
void *hash;
|
|
||||||
bool wildcard;
|
bool wildcard;
|
||||||
|
int r;
|
||||||
|
|
||||||
assert(key);
|
assert(key);
|
||||||
assert(rrsig);
|
assert(rrsig);
|
||||||
@ -746,123 +1088,15 @@ int dnssec_verify_rrset(
|
|||||||
/* Bring the RRs into canonical order */
|
/* Bring the RRs into canonical order */
|
||||||
typesafe_qsort(list, n, rr_compare);
|
typesafe_qsort(list, n, rr_compare);
|
||||||
|
|
||||||
f = open_memstream_unlocked(&sig_data, &sig_size);
|
r = dnssec_rrset_serialize_sig(rrsig, source, list, n, wildcard,
|
||||||
if (!f)
|
&sig_data, &sig_size);
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
fwrite_uint16(f, rrsig->rrsig.type_covered);
|
|
||||||
fwrite_uint8(f, rrsig->rrsig.algorithm);
|
|
||||||
fwrite_uint8(f, rrsig->rrsig.labels);
|
|
||||||
fwrite_uint32(f, rrsig->rrsig.original_ttl);
|
|
||||||
fwrite_uint32(f, rrsig->rrsig.expiration);
|
|
||||||
fwrite_uint32(f, rrsig->rrsig.inception);
|
|
||||||
fwrite_uint16(f, rrsig->rrsig.key_tag);
|
|
||||||
|
|
||||||
r = dns_name_to_wire_format(rrsig->rrsig.signer, wire_format_name, sizeof(wire_format_name), true);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
fwrite(wire_format_name, 1, r, f);
|
|
||||||
|
|
||||||
/* Convert the source of synthesis into wire format */
|
|
||||||
r = dns_name_to_wire_format(source, wire_format_name, sizeof(wire_format_name), true);
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
for (size_t k = 0; k < n; k++) {
|
r = dnssec_rrset_verify_sig(rrsig, dnskey, sig_data, sig_size);
|
||||||
size_t l;
|
if (r == -EOPNOTSUPP) {
|
||||||
|
|
||||||
rr = list[k];
|
|
||||||
|
|
||||||
/* Hash the source of synthesis. If this is a wildcard, then prefix it with the *. label */
|
|
||||||
if (wildcard)
|
|
||||||
fwrite((uint8_t[]) { 1, '*'}, sizeof(uint8_t), 2, f);
|
|
||||||
fwrite(wire_format_name, 1, r, f);
|
|
||||||
|
|
||||||
fwrite_uint16(f, rr->key->type);
|
|
||||||
fwrite_uint16(f, rr->key->class);
|
|
||||||
fwrite_uint32(f, rrsig->rrsig.original_ttl);
|
|
||||||
|
|
||||||
l = DNS_RESOURCE_RECORD_RDATA_SIZE(rr);
|
|
||||||
assert(l <= 0xFFFF);
|
|
||||||
|
|
||||||
fwrite_uint16(f, (uint16_t) l);
|
|
||||||
fwrite(DNS_RESOURCE_RECORD_RDATA(rr), 1, l, f);
|
|
||||||
}
|
|
||||||
|
|
||||||
r = fflush_and_check(f);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
initialize_libgcrypt(false);
|
|
||||||
|
|
||||||
switch (rrsig->rrsig.algorithm) {
|
|
||||||
#if GCRYPT_VERSION_NUMBER >= 0x010600
|
|
||||||
case DNSSEC_ALGORITHM_ED25519:
|
|
||||||
break;
|
|
||||||
#else
|
|
||||||
case DNSSEC_ALGORITHM_ED25519:
|
|
||||||
#endif
|
|
||||||
case DNSSEC_ALGORITHM_ED448:
|
|
||||||
*result = DNSSEC_UNSUPPORTED_ALGORITHM;
|
*result = DNSSEC_UNSUPPORTED_ALGORITHM;
|
||||||
return 0;
|
return 0;
|
||||||
default: {
|
|
||||||
gcry_error_t err;
|
|
||||||
|
|
||||||
/* OK, the RRs are now in canonical order. Let's calculate the digest */
|
|
||||||
md_algorithm = algorithm_to_gcrypt_md(rrsig->rrsig.algorithm);
|
|
||||||
if (md_algorithm == -EOPNOTSUPP) {
|
|
||||||
*result = DNSSEC_UNSUPPORTED_ALGORITHM;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (md_algorithm < 0)
|
|
||||||
return md_algorithm;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (rrsig->rrsig.algorithm) {
|
|
||||||
|
|
||||||
case DNSSEC_ALGORITHM_RSASHA1:
|
|
||||||
case DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1:
|
|
||||||
case DNSSEC_ALGORITHM_RSASHA256:
|
|
||||||
case DNSSEC_ALGORITHM_RSASHA512:
|
|
||||||
r = dnssec_rsa_verify(
|
|
||||||
gcry_md_algo_name(md_algorithm),
|
|
||||||
hash, hash_size,
|
|
||||||
rrsig,
|
|
||||||
dnskey);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DNSSEC_ALGORITHM_ECDSAP256SHA256:
|
|
||||||
case DNSSEC_ALGORITHM_ECDSAP384SHA384:
|
|
||||||
r = dnssec_ecdsa_verify(
|
|
||||||
gcry_md_algo_name(md_algorithm),
|
|
||||||
rrsig->rrsig.algorithm,
|
|
||||||
hash, hash_size,
|
|
||||||
rrsig,
|
|
||||||
dnskey);
|
|
||||||
break;
|
|
||||||
#if GCRYPT_VERSION_NUMBER >= 0x010600
|
|
||||||
case DNSSEC_ALGORITHM_ED25519:
|
|
||||||
r = dnssec_eddsa_verify(
|
|
||||||
rrsig->rrsig.algorithm,
|
|
||||||
sig_data, sig_size,
|
|
||||||
rrsig,
|
|
||||||
dnskey);
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
@ -1067,33 +1301,29 @@ int dnssec_has_rrsig(DnsAnswer *a, const DnsResourceKey *key) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int digest_to_gcrypt_md(uint8_t algorithm) {
|
static hash_md_t digest_to_hash_md(uint8_t algorithm) {
|
||||||
|
|
||||||
/* Translates a DNSSEC digest algorithm into a gcrypt digest identifier */
|
/* Translates a DNSSEC digest algorithm into an openssl/gcrypt digest identifier */
|
||||||
|
|
||||||
switch (algorithm) {
|
switch (algorithm) {
|
||||||
|
|
||||||
case DNSSEC_DIGEST_SHA1:
|
case DNSSEC_DIGEST_SHA1:
|
||||||
return GCRY_MD_SHA1;
|
return OPENSSL_OR_GCRYPT(EVP_sha1(), GCRY_MD_SHA1);
|
||||||
|
|
||||||
case DNSSEC_DIGEST_SHA256:
|
case DNSSEC_DIGEST_SHA256:
|
||||||
return GCRY_MD_SHA256;
|
return OPENSSL_OR_GCRYPT(EVP_sha256(), GCRY_MD_SHA256);
|
||||||
|
|
||||||
case DNSSEC_DIGEST_SHA384:
|
case DNSSEC_DIGEST_SHA384:
|
||||||
return GCRY_MD_SHA384;
|
return OPENSSL_OR_GCRYPT(EVP_sha384(), GCRY_MD_SHA384);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return -EOPNOTSUPP;
|
return OPENSSL_OR_GCRYPT(NULL, -EOPNOTSUPP);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int dnssec_verify_dnskey_by_ds(DnsResourceRecord *dnskey, DnsResourceRecord *ds, bool mask_revoke) {
|
int dnssec_verify_dnskey_by_ds(DnsResourceRecord *dnskey, DnsResourceRecord *ds, bool mask_revoke) {
|
||||||
uint8_t wire_format[DNS_WIRE_FORMAT_HOSTNAME_MAX];
|
uint8_t wire_format[DNS_WIRE_FORMAT_HOSTNAME_MAX];
|
||||||
_cleanup_(gcry_md_closep) gcry_md_hd_t md = NULL;
|
int r;
|
||||||
gcry_error_t err;
|
|
||||||
size_t hash_size;
|
|
||||||
int md_algorithm, r;
|
|
||||||
void *result;
|
|
||||||
|
|
||||||
assert(dnskey);
|
assert(dnskey);
|
||||||
assert(ds);
|
assert(ds);
|
||||||
@ -1116,23 +1346,65 @@ int dnssec_verify_dnskey_by_ds(DnsResourceRecord *dnskey, DnsResourceRecord *ds,
|
|||||||
if (dnssec_keytag(dnskey, mask_revoke) != ds->ds.key_tag)
|
if (dnssec_keytag(dnskey, mask_revoke) != ds->ds.key_tag)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
initialize_libgcrypt(false);
|
r = dns_name_to_wire_format(dns_resource_key_name(dnskey->key), wire_format, sizeof wire_format, true);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
md_algorithm = digest_to_gcrypt_md(ds->ds.digest_type);
|
hash_md_t md_algorithm = digest_to_hash_md(ds->ds.digest_type);
|
||||||
if (md_algorithm < 0)
|
|
||||||
return md_algorithm;
|
|
||||||
|
|
||||||
hash_size = gcry_md_get_algo_dlen(md_algorithm);
|
#if PREFER_OPENSSL
|
||||||
|
if (!md_algorithm)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
|
_cleanup_(EVP_MD_CTX_freep) EVP_MD_CTX *ctx = NULL;
|
||||||
|
uint8_t result[EVP_MAX_MD_SIZE];
|
||||||
|
|
||||||
|
unsigned hash_size = EVP_MD_size(md_algorithm);
|
||||||
assert(hash_size > 0);
|
assert(hash_size > 0);
|
||||||
|
|
||||||
if (ds->ds.digest_size != hash_size)
|
if (ds->ds.digest_size != hash_size)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
r = dns_name_to_wire_format(dns_resource_key_name(dnskey->key), wire_format, sizeof(wire_format), true);
|
ctx = EVP_MD_CTX_new();
|
||||||
if (r < 0)
|
if (!ctx)
|
||||||
return r;
|
return -ENOMEM;
|
||||||
|
|
||||||
err = gcry_md_open(&md, md_algorithm, 0);
|
if (EVP_DigestInit_ex(ctx, md_algorithm, NULL) <= 0)
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
if (EVP_DigestUpdate(ctx, wire_format, r) <= 0)
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
if (mask_revoke)
|
||||||
|
md_add_uint16(ctx, dnskey->dnskey.flags & ~DNSKEY_FLAG_REVOKE);
|
||||||
|
else
|
||||||
|
md_add_uint16(ctx, dnskey->dnskey.flags);
|
||||||
|
|
||||||
|
r = md_add_uint8(ctx, dnskey->dnskey.protocol);
|
||||||
|
if (r <= 0)
|
||||||
|
return r;
|
||||||
|
r = md_add_uint8(ctx, dnskey->dnskey.algorithm);
|
||||||
|
if (r <= 0)
|
||||||
|
return r;
|
||||||
|
if (EVP_DigestUpdate(ctx, dnskey->dnskey.key, dnskey->dnskey.key_size) <= 0)
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
if (EVP_DigestFinal_ex(ctx, result, NULL) <= 0)
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
#else
|
||||||
|
if (md_algorithm < 0)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
|
_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)
|
if (gcry_err_code(err) != GPG_ERR_NO_ERROR || !md)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
@ -1145,9 +1417,10 @@ int dnssec_verify_dnskey_by_ds(DnsResourceRecord *dnskey, DnsResourceRecord *ds,
|
|||||||
md_add_uint8(md, dnskey->dnskey.algorithm);
|
md_add_uint8(md, dnskey->dnskey.algorithm);
|
||||||
gcry_md_write(md, dnskey->dnskey.key, dnskey->dnskey.key_size);
|
gcry_md_write(md, dnskey->dnskey.key, dnskey->dnskey.key_size);
|
||||||
|
|
||||||
result = gcry_md_read(md, 0);
|
void *result = gcry_md_read(md, 0);
|
||||||
if (!result)
|
if (!result)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
#endif
|
||||||
|
|
||||||
return memcmp(result, ds->ds.digest, ds->ds.digest_size) == 0;
|
return memcmp(result, ds->ds.digest, ds->ds.digest_size) == 0;
|
||||||
}
|
}
|
||||||
@ -1190,27 +1463,22 @@ int dnssec_verify_dnskey_by_ds_search(DnsResourceRecord *dnskey, DnsAnswer *vali
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nsec3_hash_to_gcrypt_md(uint8_t algorithm) {
|
static hash_md_t nsec3_hash_to_hash_md(uint8_t algorithm) {
|
||||||
|
|
||||||
/* Translates a DNSSEC NSEC3 hash algorithm into a gcrypt digest identifier */
|
/* Translates a DNSSEC NSEC3 hash algorithm into an openssl/gcrypt digest identifier */
|
||||||
|
|
||||||
switch (algorithm) {
|
switch (algorithm) {
|
||||||
|
|
||||||
case NSEC3_ALGORITHM_SHA1:
|
case NSEC3_ALGORITHM_SHA1:
|
||||||
return GCRY_MD_SHA1;
|
return OPENSSL_OR_GCRYPT(EVP_sha1(), GCRY_MD_SHA1);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return -EOPNOTSUPP;
|
return OPENSSL_OR_GCRYPT(NULL, -EOPNOTSUPP);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int dnssec_nsec3_hash(DnsResourceRecord *nsec3, const char *name, void *ret) {
|
int dnssec_nsec3_hash(DnsResourceRecord *nsec3, const char *name, void *ret) {
|
||||||
uint8_t wire_format[DNS_WIRE_FORMAT_HOSTNAME_MAX];
|
uint8_t wire_format[DNS_WIRE_FORMAT_HOSTNAME_MAX];
|
||||||
_cleanup_(gcry_md_closep) gcry_md_hd_t md = NULL;
|
|
||||||
gcry_error_t err;
|
|
||||||
size_t hash_size;
|
|
||||||
int algorithm;
|
|
||||||
void *result;
|
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(nsec3);
|
assert(nsec3);
|
||||||
@ -1225,13 +1493,55 @@ int dnssec_nsec3_hash(DnsResourceRecord *nsec3, const char *name, void *ret) {
|
|||||||
"Ignoring NSEC3 RR %s with excessive number of iterations.",
|
"Ignoring NSEC3 RR %s with excessive number of iterations.",
|
||||||
dns_resource_record_to_string(nsec3));
|
dns_resource_record_to_string(nsec3));
|
||||||
|
|
||||||
algorithm = nsec3_hash_to_gcrypt_md(nsec3->nsec3.algorithm);
|
hash_md_t algorithm = nsec3_hash_to_hash_md(nsec3->nsec3.algorithm);
|
||||||
|
#if PREFER_OPENSSL
|
||||||
|
if (!algorithm)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
|
size_t hash_size = EVP_MD_size(algorithm);
|
||||||
|
assert(hash_size > 0);
|
||||||
|
|
||||||
|
if (nsec3->nsec3.next_hashed_name_size != hash_size)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
_cleanup_(EVP_MD_CTX_freep) EVP_MD_CTX *ctx = EVP_MD_CTX_new();
|
||||||
|
if (!ctx)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
if (EVP_DigestInit_ex(ctx, algorithm, NULL) <= 0)
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
r = dns_name_to_wire_format(name, wire_format, sizeof(wire_format), true);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
if (EVP_DigestUpdate(ctx, wire_format, r) <= 0)
|
||||||
|
return -EIO;
|
||||||
|
if (EVP_DigestUpdate(ctx, nsec3->nsec3.salt, nsec3->nsec3.salt_size) <= 0)
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
uint8_t result[EVP_MAX_MD_SIZE];
|
||||||
|
if (EVP_DigestFinal_ex(ctx, result, NULL) <= 0)
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
for (unsigned k = 0; k < nsec3->nsec3.iterations; k++) {
|
||||||
|
if (EVP_DigestInit_ex(ctx, algorithm, NULL) <= 0)
|
||||||
|
return -EIO;
|
||||||
|
if (EVP_DigestUpdate(ctx, result, hash_size) <= 0)
|
||||||
|
return -EIO;
|
||||||
|
if (EVP_DigestUpdate(ctx, nsec3->nsec3.salt, nsec3->nsec3.salt_size) <= 0)
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
if (EVP_DigestFinal_ex(ctx, result, NULL) <= 0)
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
#else
|
||||||
if (algorithm < 0)
|
if (algorithm < 0)
|
||||||
return algorithm;
|
return algorithm;
|
||||||
|
|
||||||
initialize_libgcrypt(false);
|
initialize_libgcrypt(false);
|
||||||
|
|
||||||
hash_size = gcry_md_get_algo_dlen(algorithm);
|
unsigned hash_size = gcry_md_get_algo_dlen(algorithm);
|
||||||
assert(hash_size > 0);
|
assert(hash_size > 0);
|
||||||
|
|
||||||
if (nsec3->nsec3.next_hashed_name_size != hash_size)
|
if (nsec3->nsec3.next_hashed_name_size != hash_size)
|
||||||
@ -1241,14 +1551,15 @@ int dnssec_nsec3_hash(DnsResourceRecord *nsec3, const char *name, void *ret) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
err = gcry_md_open(&md, algorithm, 0);
|
_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)
|
if (gcry_err_code(err) != GPG_ERR_NO_ERROR || !md)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
gcry_md_write(md, wire_format, r);
|
gcry_md_write(md, wire_format, r);
|
||||||
gcry_md_write(md, nsec3->nsec3.salt, nsec3->nsec3.salt_size);
|
gcry_md_write(md, nsec3->nsec3.salt, nsec3->nsec3.salt_size);
|
||||||
|
|
||||||
result = gcry_md_read(md, 0);
|
void *result = gcry_md_read(md, 0);
|
||||||
if (!result)
|
if (!result)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
@ -1264,6 +1575,7 @@ int dnssec_nsec3_hash(DnsResourceRecord *nsec3, const char *name, void *ret) {
|
|||||||
if (!result)
|
if (!result)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
memcpy(ret, result, hash_size);
|
memcpy(ret, result, hash_size);
|
||||||
return (int) hash_size;
|
return (int) hash_size;
|
||||||
@ -1283,8 +1595,14 @@ static int nsec3_is_good(DnsResourceRecord *rr, DnsResourceRecord *nsec3) {
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* Ignore NSEC3 RRs whose algorithm we don't know */
|
/* Ignore NSEC3 RRs whose algorithm we don't know */
|
||||||
if (nsec3_hash_to_gcrypt_md(rr->nsec3.algorithm) < 0)
|
#if PREFER_OPENSSL
|
||||||
|
if (!nsec3_hash_to_hash_md(rr->nsec3.algorithm))
|
||||||
return 0;
|
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 */
|
/* Ignore NSEC3 RRs with an excessive number of required iterations */
|
||||||
if (rr->nsec3.iterations > NSEC3_ITERATIONS_MAX)
|
if (rr->nsec3.iterations > NSEC3_ITERATIONS_MAX)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
|
|
||||||
#if HAVE_GCRYPT
|
#if HAVE_GCRYPT
|
||||||
#include <gcrypt.h>
|
# include <gcrypt.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "alloc-util.h"
|
#include "alloc-util.h"
|
||||||
@ -776,7 +776,7 @@ int dns_packet_append_opt(
|
|||||||
static const uint8_t rfc6975[] = {
|
static const uint8_t rfc6975[] = {
|
||||||
|
|
||||||
0, 5, /* OPTION_CODE: DAU */
|
0, 5, /* OPTION_CODE: DAU */
|
||||||
#if HAVE_GCRYPT && GCRYPT_VERSION_NUMBER >= 0x010600
|
#if PREFER_OPENSSL || (HAVE_GCRYPT && GCRYPT_VERSION_NUMBER >= 0x010600)
|
||||||
0, 7, /* LIST_LENGTH */
|
0, 7, /* LIST_LENGTH */
|
||||||
#else
|
#else
|
||||||
0, 6, /* LIST_LENGTH */
|
0, 6, /* LIST_LENGTH */
|
||||||
@ -787,7 +787,7 @@ int dns_packet_append_opt(
|
|||||||
DNSSEC_ALGORITHM_RSASHA512,
|
DNSSEC_ALGORITHM_RSASHA512,
|
||||||
DNSSEC_ALGORITHM_ECDSAP256SHA256,
|
DNSSEC_ALGORITHM_ECDSAP256SHA256,
|
||||||
DNSSEC_ALGORITHM_ECDSAP384SHA384,
|
DNSSEC_ALGORITHM_ECDSAP384SHA384,
|
||||||
#if HAVE_GCRYPT && GCRYPT_VERSION_NUMBER >= 0x010600
|
#if PREFER_OPENSSL || (HAVE_GCRYPT && GCRYPT_VERSION_NUMBER >= 0x010600)
|
||||||
DNSSEC_ALGORITHM_ED25519,
|
DNSSEC_ALGORITHM_ED25519,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -414,9 +414,9 @@ void link_set_dnssec_mode(Link *l, DnssecMode mode) {
|
|||||||
|
|
||||||
assert(l);
|
assert(l);
|
||||||
|
|
||||||
#if ! HAVE_GCRYPT
|
#if !HAVE_OPENSSL_OR_GCRYPT
|
||||||
if (IN_SET(mode, DNSSEC_YES, DNSSEC_ALLOW_DOWNGRADE))
|
if (IN_SET(mode, DNSSEC_YES, DNSSEC_ALLOW_DOWNGRADE))
|
||||||
log_warning("DNSSEC option for the link cannot be enabled or set to allow-downgrade when systemd-resolved is built without gcrypt support. Turning off DNSSEC support.");
|
log_warning("DNSSEC option for the link cannot be enabled or set to allow-downgrade when systemd-resolved is built without a cryptographic library. Turning off DNSSEC support.");
|
||||||
return;
|
return;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -1,20 +1,19 @@
|
|||||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
|
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#if HAVE_GCRYPT
|
|
||||||
#include <gcrypt.h>
|
|
||||||
#endif
|
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
|
||||||
|
#if HAVE_GCRYPT
|
||||||
|
# include <gcrypt.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "alloc-util.h"
|
#include "alloc-util.h"
|
||||||
#include "resolved-dns-dnssec.h"
|
#include "resolved-dns-dnssec.h"
|
||||||
#include "resolved-dns-rr.h"
|
#include "resolved-dns-rr.h"
|
||||||
#include "string-util.h"
|
#include "string-util.h"
|
||||||
#include "hexdecoct.h"
|
#include "hexdecoct.h"
|
||||||
|
|
||||||
#if HAVE_GCRYPT
|
|
||||||
|
|
||||||
static void test_dnssec_verify_dns_key(void) {
|
static void test_dnssec_verify_dns_key(void) {
|
||||||
|
|
||||||
static const uint8_t ds1_fprint[] = {
|
static const uint8_t ds1_fprint[] = {
|
||||||
@ -173,8 +172,8 @@ static void test_dnssec_verify_rfc8080_ed25519_example1(void) {
|
|||||||
assert_se(dns_answer_add(answer, mx, 0, DNS_ANSWER_AUTHENTICATED, NULL) >= 0);
|
assert_se(dns_answer_add(answer, mx, 0, DNS_ANSWER_AUTHENTICATED, NULL) >= 0);
|
||||||
|
|
||||||
assert_se(dnssec_verify_rrset(answer, mx->key, rrsig, dnskey,
|
assert_se(dnssec_verify_rrset(answer, mx->key, rrsig, dnskey,
|
||||||
rrsig->rrsig.inception * USEC_PER_SEC, &result) >= 0);
|
rrsig->rrsig.inception * USEC_PER_SEC, &result) >= 0);
|
||||||
#if GCRYPT_VERSION_NUMBER >= 0x010600
|
#if PREFER_OPENSSL || GCRYPT_VERSION_NUMBER >= 0x010600
|
||||||
assert_se(result == DNSSEC_VALIDATED);
|
assert_se(result == DNSSEC_VALIDATED);
|
||||||
#else
|
#else
|
||||||
assert_se(result == DNSSEC_UNSUPPORTED_ALGORITHM);
|
assert_se(result == DNSSEC_UNSUPPORTED_ALGORITHM);
|
||||||
@ -265,13 +264,196 @@ static void test_dnssec_verify_rfc8080_ed25519_example2(void) {
|
|||||||
assert_se(dns_answer_add(answer, mx, 0, DNS_ANSWER_AUTHENTICATED, NULL) >= 0);
|
assert_se(dns_answer_add(answer, mx, 0, DNS_ANSWER_AUTHENTICATED, NULL) >= 0);
|
||||||
|
|
||||||
assert_se(dnssec_verify_rrset(answer, mx->key, rrsig, dnskey,
|
assert_se(dnssec_verify_rrset(answer, mx->key, rrsig, dnskey,
|
||||||
rrsig->rrsig.inception * USEC_PER_SEC, &result) >= 0);
|
rrsig->rrsig.inception * USEC_PER_SEC, &result) >= 0);
|
||||||
#if GCRYPT_VERSION_NUMBER >= 0x010600
|
#if PREFER_OPENSSL || GCRYPT_VERSION_NUMBER >= 0x010600
|
||||||
assert_se(result == DNSSEC_VALIDATED);
|
assert_se(result == DNSSEC_VALIDATED);
|
||||||
#else
|
#else
|
||||||
assert_se(result == DNSSEC_UNSUPPORTED_ALGORITHM);
|
assert_se(result == DNSSEC_UNSUPPORTED_ALGORITHM);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_dnssec_verify_rfc6605_example1(void) {
|
||||||
|
static const uint8_t signature_blob[] = {
|
||||||
|
0xab, 0x1e, 0xb0, 0x2d, 0x8a, 0xa6, 0x87, 0xe9, 0x7d, 0xa0, 0x22, 0x93, 0x37, 0xaa, 0x88, 0x73,
|
||||||
|
0xe6, 0xf0, 0xeb, 0x26, 0xbe, 0x28, 0x9f, 0x28, 0x33, 0x3d, 0x18, 0x3f, 0x5d, 0x3b, 0x7a, 0x95,
|
||||||
|
0xc0, 0xc8, 0x69, 0xad, 0xfb, 0x74, 0x8d, 0xae, 0xe3, 0xc5, 0x28, 0x6e, 0xed, 0x66, 0x82, 0xc1,
|
||||||
|
0x2e, 0x55, 0x33, 0x18, 0x6b, 0xac, 0xed, 0x9c, 0x26, 0xc1, 0x67, 0xa9, 0xeb, 0xae, 0x95, 0x0b,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint8_t ds_fprint[] = {
|
||||||
|
0x6f, 0x87, 0x3c, 0x73, 0x57, 0xde, 0xd9, 0xee, 0xf8, 0xef, 0xbd, 0x76, 0xed, 0xbd, 0xbb, 0xd7,
|
||||||
|
0x5e, 0x7a, 0xe7, 0xa6, 0x9d, 0xeb, 0x6e, 0x7a, 0x7f, 0x8d, 0xb8, 0xeb, 0x6e, 0x5b, 0x7f, 0x97,
|
||||||
|
0x35, 0x7b, 0x6e, 0xfb, 0xd1, 0xc7, 0xba, 0x77, 0xa7, 0xb7, 0xed, 0xd7, 0xfa, 0xd5, 0xdd, 0x7b,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint8_t dnskey_blob[] = {
|
||||||
|
0x1a, 0x88, 0xc8, 0x86, 0x15, 0xd4, 0x37, 0xfb, 0xb8, 0xbf, 0x9e, 0x19, 0x42, 0xa1, 0x92, 0x9f,
|
||||||
|
0x28, 0x56, 0x27, 0x06, 0xae, 0x6c, 0x2b, 0xd3, 0x99, 0xe7, 0xb1, 0xbf, 0xb6, 0xd1, 0xe9, 0xe7,
|
||||||
|
0x5b, 0x92, 0xb4, 0xaa, 0x42, 0x91, 0x7a, 0xe1, 0xc6, 0x1b, 0x70, 0x1e, 0xf0, 0x35, 0xc3, 0xfe,
|
||||||
|
0x7b, 0xe3, 0x00, 0x9c, 0xba, 0xfe, 0x5a, 0x2f, 0x71, 0x31, 0x6c, 0x90, 0x2d, 0xcf, 0x0d, 0x00,
|
||||||
|
};
|
||||||
|
|
||||||
|
_cleanup_(dns_resource_record_unrefp) DnsResourceRecord *dnskey = NULL, *ds = NULL, *a = NULL,
|
||||||
|
*rrsig = NULL;
|
||||||
|
_cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
|
||||||
|
DnssecResult result;
|
||||||
|
|
||||||
|
dnskey = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DNSKEY, "example.net.");
|
||||||
|
assert_se(dnskey);
|
||||||
|
|
||||||
|
dnskey->dnskey.flags = 257;
|
||||||
|
dnskey->dnskey.protocol = 3;
|
||||||
|
dnskey->dnskey.algorithm = DNSSEC_ALGORITHM_ECDSAP256SHA256;
|
||||||
|
dnskey->dnskey.key_size = sizeof(dnskey_blob);
|
||||||
|
dnskey->dnskey.key = memdup(dnskey_blob, sizeof(dnskey_blob));
|
||||||
|
assert_se(dnskey->dnskey.key);
|
||||||
|
|
||||||
|
log_info("DNSKEY: %s", strna(dns_resource_record_to_string(dnskey)));
|
||||||
|
|
||||||
|
ds = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DS, "example.net.");
|
||||||
|
assert_se(ds);
|
||||||
|
|
||||||
|
ds->ds.key_tag = 55648;
|
||||||
|
ds->ds.algorithm = DNSSEC_ALGORITHM_ECDSAP256SHA256;
|
||||||
|
ds->ds.digest_type = DNSSEC_DIGEST_SHA256;
|
||||||
|
ds->ds.digest_size = sizeof(ds_fprint);
|
||||||
|
ds->ds.digest = memdup(ds_fprint, ds->ds.digest_size);
|
||||||
|
assert_se(ds->ds.digest);
|
||||||
|
|
||||||
|
log_info("DS: %s", strna(dns_resource_record_to_string(ds)));
|
||||||
|
|
||||||
|
a = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_A, "www.example.net");
|
||||||
|
assert_se(a);
|
||||||
|
|
||||||
|
a->a.in_addr.s_addr = inet_addr("192.0.2.1");
|
||||||
|
|
||||||
|
log_info("A: %s", strna(dns_resource_record_to_string(a)));
|
||||||
|
|
||||||
|
rrsig = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_RRSIG, "www.example.net.");
|
||||||
|
assert_se(rrsig);
|
||||||
|
|
||||||
|
rrsig->rrsig.type_covered = DNS_TYPE_A;
|
||||||
|
rrsig->rrsig.algorithm = DNSSEC_ALGORITHM_ECDSAP256SHA256;
|
||||||
|
rrsig->rrsig.labels = 3;
|
||||||
|
rrsig->rrsig.expiration = 1284026679;
|
||||||
|
rrsig->rrsig.inception = 1281607479;
|
||||||
|
rrsig->rrsig.key_tag = 55648;
|
||||||
|
rrsig->rrsig.original_ttl = 3600;
|
||||||
|
rrsig->rrsig.signer = strdup("example.net.");
|
||||||
|
assert_se(rrsig->rrsig.signer);
|
||||||
|
rrsig->rrsig.signature_size = sizeof(signature_blob);
|
||||||
|
rrsig->rrsig.signature = memdup(signature_blob, rrsig->rrsig.signature_size);
|
||||||
|
assert_se(rrsig->rrsig.signature);
|
||||||
|
|
||||||
|
log_info("RRSIG: %s", strna(dns_resource_record_to_string(rrsig)));
|
||||||
|
|
||||||
|
assert_se(dnssec_key_match_rrsig(a->key, rrsig) > 0);
|
||||||
|
assert_se(dnssec_rrsig_match_dnskey(rrsig, dnskey, false) > 0);
|
||||||
|
|
||||||
|
answer = dns_answer_new(1);
|
||||||
|
assert_se(answer);
|
||||||
|
assert_se(dns_answer_add(answer, a, 0, DNS_ANSWER_AUTHENTICATED, NULL) >= 0);
|
||||||
|
|
||||||
|
assert_se(dnssec_verify_rrset(answer, a->key, rrsig, dnskey,
|
||||||
|
rrsig->rrsig.inception * USEC_PER_SEC, &result) >= 0);
|
||||||
|
assert_se(result == DNSSEC_VALIDATED);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_dnssec_verify_rfc6605_example2(void) {
|
||||||
|
static const uint8_t signature_blob[] = {
|
||||||
|
0xfc, 0xbe, 0x61, 0x0c, 0xa2, 0x2f, 0x18, 0x3c, 0x88, 0xd5, 0xf7, 0x00, 0x45, 0x7d, 0xf3, 0xeb,
|
||||||
|
0x9a, 0xab, 0x98, 0xfb, 0x15, 0xcf, 0xbd, 0xd0, 0x0f, 0x53, 0x2b, 0xe4, 0x21, 0x2a, 0x3a, 0x22,
|
||||||
|
0xcf, 0xf7, 0x98, 0x71, 0x42, 0x8b, 0xae, 0xae, 0x81, 0x82, 0x79, 0x93, 0xaf, 0xcc, 0x56, 0xb1,
|
||||||
|
0xb1, 0x3f, 0x06, 0x96, 0xbe, 0xf8, 0x85, 0xb6, 0xaf, 0x44, 0xa6, 0xb2, 0x24, 0xdb, 0xb2, 0x74,
|
||||||
|
0x2b, 0xb3, 0x59, 0x34, 0x92, 0x3d, 0xdc, 0xfb, 0xc2, 0x7a, 0x97, 0x2f, 0x96, 0xdd, 0x70, 0x9c,
|
||||||
|
0xee, 0xb1, 0xd9, 0xc8, 0xd1, 0x14, 0x8c, 0x44, 0xec, 0x71, 0xc0, 0x68, 0xa9, 0x59, 0xc2, 0x66,
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint8_t ds_fprint[] = {
|
||||||
|
0xef, 0x67, 0x7b, 0x6f, 0xad, 0xbd, 0xef, 0xa7, 0x1e, 0xd3, 0xae, 0x37, 0xf1, 0xef, 0x5c, 0xd1,
|
||||||
|
0xb7, 0xf7, 0xd7, 0xdd, 0x35, 0xdd, 0xc7, 0xfc, 0xd3, 0x57, 0xf4, 0xf5, 0xe7, 0x1c, 0xf3, 0x86,
|
||||||
|
0xfc, 0x77, 0xb7, 0xbd, 0xe3, 0xde, 0x5f, 0xdb, 0xb7, 0xb7, 0xd3, 0x97, 0x3a, 0x6b, 0xd6, 0xf4,
|
||||||
|
0xe7, 0xad, 0xda, 0xf5, 0xbe, 0x5f, 0xe1, 0xdd, 0xbc, 0xf3, 0x8d, 0x39, 0x73, 0x7d, 0x34, 0xf1,
|
||||||
|
0xaf, 0x78, 0xe9, 0xd7, 0xfd, 0xf3, 0x77, 0x7a,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint8_t dnskey_blob[] = {
|
||||||
|
0xc4, 0xa6, 0x1a, 0x36, 0x15, 0x9d, 0x18, 0xe7, 0xc9, 0xfa, 0x73, 0xeb, 0x2f, 0xcf, 0xda, 0xae,
|
||||||
|
0x4c, 0x1f, 0xd8, 0x46, 0x37, 0x30, 0x32, 0x7e, 0x48, 0x4a, 0xca, 0x8a, 0xf0, 0x55, 0x4a, 0xe9,
|
||||||
|
0xb5, 0xc3, 0xf7, 0xa0, 0xb1, 0x7b, 0xd2, 0x00, 0x3b, 0x4d, 0x26, 0x1c, 0x9e, 0x9b, 0x94, 0x42,
|
||||||
|
0x3a, 0x98, 0x10, 0xe8, 0xaf, 0x17, 0xd4, 0x34, 0x52, 0x12, 0x4a, 0xdb, 0x61, 0x0f, 0x8e, 0x07,
|
||||||
|
0xeb, 0xfc, 0xfe, 0xe5, 0xf8, 0xe4, 0xd0, 0x70, 0x63, 0xca, 0xe9, 0xeb, 0x91, 0x7a, 0x1a, 0x5b,
|
||||||
|
0xab, 0xf0, 0x8f, 0xe6, 0x95, 0x53, 0x60, 0x17, 0xa5, 0xbf, 0xa9, 0x32, 0x37, 0xee, 0x6e, 0x34,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
_cleanup_(dns_resource_record_unrefp) DnsResourceRecord *dnskey = NULL, *ds = NULL, *a = NULL,
|
||||||
|
*rrsig = NULL;
|
||||||
|
_cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
|
||||||
|
DnssecResult result;
|
||||||
|
|
||||||
|
dnskey = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DNSKEY, "example.net.");
|
||||||
|
assert_se(dnskey);
|
||||||
|
|
||||||
|
dnskey->dnskey.flags = 257;
|
||||||
|
dnskey->dnskey.protocol = 3;
|
||||||
|
dnskey->dnskey.algorithm = DNSSEC_ALGORITHM_ECDSAP384SHA384;
|
||||||
|
dnskey->dnskey.key_size = sizeof(dnskey_blob);
|
||||||
|
dnskey->dnskey.key = memdup(dnskey_blob, sizeof(dnskey_blob));
|
||||||
|
assert_se(dnskey->dnskey.key);
|
||||||
|
|
||||||
|
log_info("DNSKEY: %s", strna(dns_resource_record_to_string(dnskey)));
|
||||||
|
|
||||||
|
ds = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DS, "example.net.");
|
||||||
|
assert_se(ds);
|
||||||
|
|
||||||
|
ds->ds.key_tag = 10771;
|
||||||
|
ds->ds.algorithm = DNSSEC_ALGORITHM_ECDSAP384SHA384;
|
||||||
|
ds->ds.digest_type = DNSSEC_DIGEST_SHA384;
|
||||||
|
ds->ds.digest_size = sizeof(ds_fprint);
|
||||||
|
ds->ds.digest = memdup(ds_fprint, ds->ds.digest_size);
|
||||||
|
assert_se(ds->ds.digest);
|
||||||
|
|
||||||
|
log_info("DS: %s", strna(dns_resource_record_to_string(ds)));
|
||||||
|
|
||||||
|
a = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_A, "www.example.net");
|
||||||
|
assert_se(a);
|
||||||
|
|
||||||
|
a->a.in_addr.s_addr = inet_addr("192.0.2.1");
|
||||||
|
|
||||||
|
log_info("A: %s", strna(dns_resource_record_to_string(a)));
|
||||||
|
|
||||||
|
rrsig = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_RRSIG, "www.example.net.");
|
||||||
|
assert_se(rrsig);
|
||||||
|
|
||||||
|
rrsig->rrsig.type_covered = DNS_TYPE_A;
|
||||||
|
rrsig->rrsig.algorithm = DNSSEC_ALGORITHM_ECDSAP384SHA384;
|
||||||
|
rrsig->rrsig.labels = 3;
|
||||||
|
rrsig->rrsig.expiration = 1284027625;
|
||||||
|
rrsig->rrsig.inception = 1281608425;
|
||||||
|
rrsig->rrsig.key_tag = 10771;
|
||||||
|
rrsig->rrsig.original_ttl = 3600;
|
||||||
|
rrsig->rrsig.signer = strdup("example.net.");
|
||||||
|
assert_se(rrsig->rrsig.signer);
|
||||||
|
rrsig->rrsig.signature_size = sizeof(signature_blob);
|
||||||
|
rrsig->rrsig.signature = memdup(signature_blob, rrsig->rrsig.signature_size);
|
||||||
|
assert_se(rrsig->rrsig.signature);
|
||||||
|
|
||||||
|
log_info("RRSIG: %s", strna(dns_resource_record_to_string(rrsig)));
|
||||||
|
|
||||||
|
assert_se(dnssec_key_match_rrsig(a->key, rrsig) > 0);
|
||||||
|
assert_se(dnssec_rrsig_match_dnskey(rrsig, dnskey, false) > 0);
|
||||||
|
|
||||||
|
answer = dns_answer_new(1);
|
||||||
|
assert_se(answer);
|
||||||
|
assert_se(dns_answer_add(answer, a, 0, DNS_ANSWER_AUTHENTICATED, NULL) >= 0);
|
||||||
|
|
||||||
|
assert_se(dnssec_verify_rrset(answer, a->key, rrsig, dnskey,
|
||||||
|
rrsig->rrsig.inception * USEC_PER_SEC, &result) >= 0);
|
||||||
|
assert_se(result == DNSSEC_VALIDATED);
|
||||||
|
}
|
||||||
|
|
||||||
static void test_dnssec_verify_rrset(void) {
|
static void test_dnssec_verify_rrset(void) {
|
||||||
|
|
||||||
static const uint8_t signature_blob[] = {
|
static const uint8_t signature_blob[] = {
|
||||||
@ -605,19 +787,16 @@ static void test_dnssec_nsec3_hash(void) {
|
|||||||
assert_se(strcasecmp(b, "PJ8S08RR45VIQDAQGE7EN3VHKNROTBMM") == 0);
|
assert_se(strcasecmp(b, "PJ8S08RR45VIQDAQGE7EN3VHKNROTBMM") == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
|
|
||||||
#if HAVE_GCRYPT
|
|
||||||
test_dnssec_verify_dns_key();
|
test_dnssec_verify_dns_key();
|
||||||
test_dnssec_verify_rfc8080_ed25519_example1();
|
test_dnssec_verify_rfc8080_ed25519_example1();
|
||||||
test_dnssec_verify_rfc8080_ed25519_example2();
|
test_dnssec_verify_rfc8080_ed25519_example2();
|
||||||
|
test_dnssec_verify_rfc6605_example1();
|
||||||
|
test_dnssec_verify_rfc6605_example2();
|
||||||
test_dnssec_verify_rrset();
|
test_dnssec_verify_rrset();
|
||||||
test_dnssec_verify_rrset2();
|
test_dnssec_verify_rrset2();
|
||||||
test_dnssec_verify_rrset3();
|
test_dnssec_verify_rrset3();
|
||||||
test_dnssec_nsec3_hash();
|
test_dnssec_nsec3_hash();
|
||||||
#endif
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -2,8 +2,46 @@
|
|||||||
|
|
||||||
#include "openssl-util.h"
|
#include "openssl-util.h"
|
||||||
#include "alloc-util.h"
|
#include "alloc-util.h"
|
||||||
|
#include "hexdecoct.h"
|
||||||
|
|
||||||
#if HAVE_OPENSSL
|
#if HAVE_OPENSSL
|
||||||
|
int openssl_hash(const EVP_MD *alg,
|
||||||
|
const void *msg,
|
||||||
|
size_t msg_len,
|
||||||
|
uint8_t *ret_hash,
|
||||||
|
size_t *ret_hash_len) {
|
||||||
|
|
||||||
|
_cleanup_(EVP_MD_CTX_freep) EVP_MD_CTX *ctx = NULL;
|
||||||
|
unsigned len;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
ctx = EVP_MD_CTX_new();
|
||||||
|
if (!ctx)
|
||||||
|
/* This function just calls OPENSSL_zalloc, so failure
|
||||||
|
* here is almost certainly a failed allocation. */
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
/* The documentation claims EVP_DigestInit behaves just like
|
||||||
|
* EVP_DigestInit_ex if passed NULL, except it also calls
|
||||||
|
* EVP_MD_CTX_reset, which deinitializes the context. */
|
||||||
|
r = EVP_DigestInit_ex(ctx, alg, NULL);
|
||||||
|
if (r == 0)
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
r = EVP_DigestUpdate(ctx, msg, msg_len);
|
||||||
|
if (r == 0)
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
r = EVP_DigestFinal_ex(ctx, ret_hash, &len);
|
||||||
|
if (r == 0)
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
if (ret_hash_len)
|
||||||
|
*ret_hash_len = len;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int rsa_encrypt_bytes(
|
int rsa_encrypt_bytes(
|
||||||
EVP_PKEY *pkey,
|
EVP_PKEY *pkey,
|
||||||
const void *decrypted_key,
|
const void *decrypted_key,
|
||||||
@ -70,4 +108,33 @@ int rsa_pkey_to_suitable_key_size(
|
|||||||
*ret_suitable_key_size = suitable_key_size;
|
*ret_suitable_key_size = suitable_key_size;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# if PREFER_OPENSSL
|
||||||
|
int string_hashsum(
|
||||||
|
const char *s,
|
||||||
|
size_t len,
|
||||||
|
const EVP_MD *md_algorithm,
|
||||||
|
char **ret) {
|
||||||
|
|
||||||
|
uint8_t hash[EVP_MAX_MD_SIZE];
|
||||||
|
size_t hash_size;
|
||||||
|
char *enc;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
hash_size = EVP_MD_size(md_algorithm);
|
||||||
|
assert(hash_size > 0);
|
||||||
|
|
||||||
|
r = openssl_hash(md_algorithm, s, len, hash, NULL);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
enc = hexmem(hash, hash_size);
|
||||||
|
if (!enc)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
*ret = enc;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
@ -5,6 +5,8 @@
|
|||||||
|
|
||||||
#if HAVE_OPENSSL
|
#if HAVE_OPENSSL
|
||||||
# include <openssl/bio.h>
|
# include <openssl/bio.h>
|
||||||
|
# include <openssl/bn.h>
|
||||||
|
# include <openssl/err.h>
|
||||||
# include <openssl/evp.h>
|
# include <openssl/evp.h>
|
||||||
# include <openssl/pkcs7.h>
|
# include <openssl/pkcs7.h>
|
||||||
# include <openssl/ssl.h>
|
# include <openssl/ssl.h>
|
||||||
@ -13,7 +15,15 @@
|
|||||||
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(X509*, X509_free, NULL);
|
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(X509*, X509_free, NULL);
|
||||||
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(X509_NAME*, X509_NAME_free, NULL);
|
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(X509_NAME*, X509_NAME_free, NULL);
|
||||||
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(EVP_PKEY_CTX*, EVP_PKEY_CTX_free, NULL);
|
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(EVP_PKEY_CTX*, EVP_PKEY_CTX_free, NULL);
|
||||||
|
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(EVP_PKEY*, EVP_PKEY_free, NULL);
|
||||||
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(EVP_CIPHER_CTX*, EVP_CIPHER_CTX_free, NULL);
|
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(EVP_CIPHER_CTX*, EVP_CIPHER_CTX_free, NULL);
|
||||||
|
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(RSA*, RSA_free, NULL);
|
||||||
|
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(EC_KEY*, EC_KEY_free, NULL);
|
||||||
|
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(EC_POINT*, EC_POINT_free, NULL);
|
||||||
|
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(EC_GROUP*, EC_GROUP_free, NULL);
|
||||||
|
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(BIGNUM*, BN_free, NULL);
|
||||||
|
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(BN_CTX*, BN_CTX_free, NULL);
|
||||||
|
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(ECDSA_SIG*, ECDSA_SIG_free, NULL);
|
||||||
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(PKCS7*, PKCS7_free, NULL);
|
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(PKCS7*, PKCS7_free, NULL);
|
||||||
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(SSL*, SSL_free, NULL);
|
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(SSL*, SSL_free, NULL);
|
||||||
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(BIO*, BIO_free, NULL);
|
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(BIO*, BIO_free, NULL);
|
||||||
@ -26,8 +36,41 @@ static inline void sk_X509_free_allp(STACK_OF(X509) **sk) {
|
|||||||
sk_X509_pop_free(*sk, X509_free);
|
sk_X509_pop_free(*sk, X509_free);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int openssl_hash(const EVP_MD *alg, const void *msg, size_t msg_len, uint8_t *ret_hash, size_t *ret_hash_len);
|
||||||
|
|
||||||
int rsa_encrypt_bytes(EVP_PKEY *pkey, const void *decrypted_key, size_t decrypted_key_size, void **ret_encrypt_key, size_t *ret_encrypt_key_size);
|
int rsa_encrypt_bytes(EVP_PKEY *pkey, const void *decrypted_key, size_t decrypted_key_size, void **ret_encrypt_key, size_t *ret_encrypt_key_size);
|
||||||
|
|
||||||
int rsa_pkey_to_suitable_key_size(EVP_PKEY *pkey, size_t *ret_suitable_key_size);
|
int rsa_pkey_to_suitable_key_size(EVP_PKEY *pkey, size_t *ret_suitable_key_size);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#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, hash_algorithm_t md_algorithm, char **ret);
|
||||||
|
|
||||||
|
static inline int string_hashsum_sha224(const char *s, size_t len, char **ret) {
|
||||||
|
return string_hashsum(s, len, EVP_sha224(), ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int string_hashsum_sha256(const char *s, size_t len, char **ret) {
|
||||||
|
return string_hashsum(s, len, EVP_sha256(), ret);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -594,8 +594,10 @@ tests += [
|
|||||||
|
|
||||||
[['src/test/test-id128.c']],
|
[['src/test/test-id128.c']],
|
||||||
|
|
||||||
[['src/test/test-gcrypt-util.c'],
|
[['src/test/test-cryptolib.c'],
|
||||||
[], [], [], 'HAVE_GCRYPT'],
|
[libshared],
|
||||||
|
[lib_openssl_or_gcrypt],
|
||||||
|
[], 'HAVE_OPENSSL_OR_GCRYPT'],
|
||||||
|
|
||||||
[['src/test/test-nss-hosts.c',
|
[['src/test/test-nss-hosts.c',
|
||||||
'src/test/nss-test-util.c',
|
'src/test/nss-test-util.c',
|
||||||
|
@ -3,25 +3,34 @@
|
|||||||
#include "alloc-util.h"
|
#include "alloc-util.h"
|
||||||
#include "gcrypt-util.h"
|
#include "gcrypt-util.h"
|
||||||
#include "macro.h"
|
#include "macro.h"
|
||||||
|
#include "openssl-util.h"
|
||||||
#include "string-util.h"
|
#include "string-util.h"
|
||||||
#include "tests.h"
|
#include "tests.h"
|
||||||
|
|
||||||
TEST(string_hashsum) {
|
TEST(string_hashsum) {
|
||||||
_cleanup_free_ char *out1 = NULL, *out2 = NULL, *out3 = NULL, *out4 = NULL;
|
_cleanup_free_ char *out1 = NULL, *out2 = NULL, *out3 = NULL, *out4 = NULL;
|
||||||
|
|
||||||
assert_se(string_hashsum("asdf", 4, GCRY_MD_SHA224, &out1) == 0);
|
assert_se(string_hashsum("asdf", 4,
|
||||||
|
OPENSSL_OR_GCRYPT(EVP_sha224(), GCRY_MD_SHA224),
|
||||||
|
&out1) == 0);
|
||||||
/* echo -n 'asdf' | sha224sum - */
|
/* echo -n 'asdf' | sha224sum - */
|
||||||
assert_se(streq(out1, "7872a74bcbf298a1e77d507cd95d4f8d96131cbbd4cdfc571e776c8a"));
|
assert_se(streq(out1, "7872a74bcbf298a1e77d507cd95d4f8d96131cbbd4cdfc571e776c8a"));
|
||||||
|
|
||||||
assert_se(string_hashsum("asdf", 4, GCRY_MD_SHA256, &out2) == 0);
|
assert_se(string_hashsum("asdf", 4,
|
||||||
|
OPENSSL_OR_GCRYPT(EVP_sha256(), GCRY_MD_SHA256),
|
||||||
|
&out2) == 0);
|
||||||
/* echo -n 'asdf' | sha256sum - */
|
/* echo -n 'asdf' | sha256sum - */
|
||||||
assert_se(streq(out2, "f0e4c2f76c58916ec258f246851bea091d14d4247a2fc3e18694461b1816e13b"));
|
assert_se(streq(out2, "f0e4c2f76c58916ec258f246851bea091d14d4247a2fc3e18694461b1816e13b"));
|
||||||
|
|
||||||
assert_se(string_hashsum("", 0, GCRY_MD_SHA224, &out3) == 0);
|
assert_se(string_hashsum("", 0,
|
||||||
|
OPENSSL_OR_GCRYPT(EVP_sha224(), GCRY_MD_SHA224),
|
||||||
|
&out3) == 0);
|
||||||
/* echo -n '' | sha224sum - */
|
/* echo -n '' | sha224sum - */
|
||||||
assert_se(streq(out3, "d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f"));
|
assert_se(streq(out3, "d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f"));
|
||||||
|
|
||||||
assert_se(string_hashsum("", 0, GCRY_MD_SHA256, &out4) == 0);
|
assert_se(string_hashsum("", 0,
|
||||||
|
OPENSSL_OR_GCRYPT(EVP_sha256(), GCRY_MD_SHA256),
|
||||||
|
&out4) == 0);
|
||||||
/* echo -n '' | sha256sum - */
|
/* echo -n '' | sha256sum - */
|
||||||
assert_se(streq(out4, "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"));
|
assert_se(streq(out4, "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"));
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user