1
0
mirror of https://github.com/systemd/systemd synced 2026-04-09 16:44:51 +02:00

Compare commits

..

17 Commits

Author SHA1 Message Date
Franck Bui
4c733d3046 Bump the max number of inodes for /dev to 128k
Follow-up for 7d85383edbab73274dc81cc888d884bb01070bc2.

Apparently the previous limit set on the max number of inodes for /dev was too
small as a system with 4096 LUNs attached can consume up to 95k inodes for
symlinks:

  # /bin/df -i
  Filesystem                 Inodes  IUsed    IFree IUse% Mounted on
  devtmpfs                 49274377  95075 49179302    1% /dev

Hence this patch bumps the limit from 64k to 128k although the new limit is
still pretty arbitrary (that said, not sure if it really makes sense to put
such absolute limit number).
2021-12-03 14:23:25 +00:00
Zbigniew Jędrzejewski-Szmek
939387bdc6
Merge pull request #21170 from keszybz/delibgcryptify
Allow systemd-resolved and systemd-importd to use libgcrypt or libopenssl
2021-12-03 13:44:53 +01:00
Zbigniew Jędrzejewski-Szmek
e37ad765c8 meson: disallow the combination of cryptolib=openssl and dns-over-tls=gnutls
It could work, but it doesn't make much sense. If we already have openssl as
the cryptolib that provides the necessary support, let's not bring in another
library. Disallowing this simplifies things and reduces our support matrix.
2021-12-02 11:31:20 +01:00
Zbigniew Jędrzejewski-Szmek
85bd394df5 ci: expand the test framework to cover openssl 2021-12-02 11:31:20 +01:00
Zbigniew Jędrzejewski-Szmek
684e0a5605 ci: temporarily set -Wno-deprecated-declarations in Packit
to suppress OpenSSL 3.0 deprecation warnings (until a proper solution is
deployed): RSA_free, EC_KEY_free, RSA_set0_key, RSA_size, EVP_PKEY_assign,
EC_KEY_set_group, and others are deprecated.
2021-12-01 12:36:57 +01:00
Zbigniew Jędrzejewski-Szmek
6e7323137a resolved: do not use BN_dup() unnecessarilly
Suggested in https://github.com/systemd/systemd/pull/21170#discussion_r738696794
2021-12-01 12:36:57 +01:00
Zbigniew Jędrzejewski-Szmek
7e8facb36b port string_hashsum from libgcrypt to openssl^gcrypt
This allows resolved and importd to be built without libgcrypt.

Note that we now say either 'cryptographic library' or 'cryptolib'.

Co-authored-by: Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
2021-12-01 12:36:57 +01:00
Kevin Kuehler
fc169a6fb2 basic/openssl-util: Add sha256 hash wrapper 2021-12-01 12:36:57 +01:00
Kevin Kuehler
1736344e9e resolve: Port nsec3 code to openssl^gcrypt
Co-authored-by: Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
2021-12-01 12:36:45 +01:00
Kevin Kuehler
1cd7a2c172 resolve: Port dnskey verification by ds to openssl^gcrypt
Co-authored-by: Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
2021-11-30 23:00:21 +01:00
Kevin Kuehler
0351cbb9e4 resolve: Port dnssec verify from gcrypt to openssl^gcrypt
Co-authored-by: Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
2021-11-30 23:00:21 +01:00
Zbigniew Jędrzejewski-Szmek
667dac6ed6 resolved: split out function to hash signature
dnssec_verify_rrset() is just too long.
2021-11-30 23:00:21 +01:00
Zbigniew Jędrzejewski-Szmek
cc1ecbaaf3 resolved: split out function to generate signature
dnssec_verify_rrset() is just too long.
2021-11-30 23:00:21 +01:00
Kevin Kuehler
bf4b1adf6f resolve: Add coverage for dnssec ecdsa (rfc6605) 2021-11-30 23:00:21 +01:00
Zbigniew Jędrzejewski-Szmek
6214d42bd2 import: port importd from libgcrypt to openssl^gcrypt
This is heavily based on Kevin Kuehler's work, but the logic is also
significantly changed: instead of a straighforward port to openssl, both
versions of the code are kept, and at compile time we pick one or the other.

The code is purposefully kept "dumb" — the idea is that the libgcrypt codepaths
are only temporary and will be removed after everybody upgrades to openssl 3.
Thus, a separate abstraction layer is not introduced. Instead, very simple
ifdefs are used to select one or the other. If we added an abstraction layer,
we'd have to remove it again afterwards, and it don't think it makes sense to
do that for a temporary solution.

Co-authored-by: Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>

# Conflicts:
#	meson.build
2021-11-30 23:00:21 +01:00
Zbigniew Jędrzejewski-Szmek
57633d2376 meson: add config setting to select between openssl and gcrypt
This is not pretty, but it is supposed to be only a temporary measure.
2021-11-30 23:00:21 +01:00
Kevin Kuehler
ade99252e2 repart: port to our home-grown hmac_sha256
This reduces dependencies. The speed of the code here is uimportant, because we
hash only a tiny amount of input data.

Debian and Ubuntu currently build without repart, see
https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=976959
> repart requires openssl and so far I tried to avoid linking against
> both gnutls and openssl.

Co-authored-by: Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
2021-11-30 23:00:21 +01:00
24 changed files with 1007 additions and 302 deletions

View File

@ -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)

View File

@ -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 }}

View File

@ -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
View File

@ -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

View File

@ -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

View File

@ -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'],

View File

@ -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"

View File

@ -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;
@ -48,3 +49,4 @@ int string_hashsum(const char *s, size_t len, int md_algorithm, char **out) {
return 0; return 0;
} }
# endif # endif
#endif

View File

@ -12,11 +12,15 @@
#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);
@ -32,3 +36,4 @@ static inline int string_hashsum_sha256(const char *s, size_t len, char **out) {
return -EOPNOTSUPP; return -EOPNOTSUPP;
# endif # endif
} }
#endif

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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]],
] ]

View File

@ -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"

View File

@ -498,9 +498,9 @@ 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

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -1,11 +1,12 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <arpa/inet.h> #include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#if HAVE_GCRYPT #if HAVE_GCRYPT
# include <gcrypt.h> # include <gcrypt.h>
#endif #endif
#include <netinet/in.h>
#include <sys/socket.h>
#include "alloc-util.h" #include "alloc-util.h"
#include "resolved-dns-dnssec.h" #include "resolved-dns-dnssec.h"
@ -13,8 +14,6 @@
#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[] = {
@ -174,7 +173,7 @@ static void test_dnssec_verify_rfc8080_ed25519_example1(void) {
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);
@ -266,12 +265,195 @@ static void test_dnssec_verify_rfc8080_ed25519_example2(void) {
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;
} }

View File

@ -11,9 +11,9 @@
#include "errno-util.h" #include "errno-util.h"
#include "macro.h" #include "macro.h"
/* 4MB for contents of regular files, 64k inodes for directories, symbolic links and device specials, using /* 4MB for contents of regular files, 128k inodes for directories, symbolic links and device specials, using
* large storage array systems as a baseline */ * large storage array systems as a baseline */
#define TMPFS_LIMITS_DEV ",size=4m,nr_inodes=64k" #define TMPFS_LIMITS_DEV ",size=4m,nr_inodes=128k"
/* Very little, if any use expected */ /* Very little, if any use expected */
#define TMPFS_LIMITS_EMPTY_OR_ALMOST ",size=4m,nr_inodes=1k" #define TMPFS_LIMITS_EMPTY_OR_ALMOST ",size=4m,nr_inodes=1k"

View File

@ -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

View File

@ -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

View File

@ -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',

View File

@ -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"));
} }