diff options
author | Luca Boccassi <luca.boccassi@microsoft.com> | 2021-10-09 19:37:59 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-10-09 19:37:59 +0200 |
commit | ccf609c88cacddcb5417d1aa1b9f56e55be45379 (patch) | |
tree | db21f181f58dd56f5bba51ef2c9252dbbff500d7 | |
parent | test: set 5 minute timeout on TEST-11-ISSUE-3166 and TEST-50-DISSECT (diff) | |
parent | Add benchmark for sha256 calculations (diff) | |
download | systemd-ccf609c88cacddcb5417d1aa1b9f56e55be45379.tar.xz systemd-ccf609c88cacddcb5417d1aa1b9f56e55be45379.zip |
Merge pull request #20915 from bluca/libsystemd_openssl
libsystemd/sd-id128: use only internal hmac, remove khash/OpenSSL support
-rw-r--r-- | LICENSES/README.md | 5 | ||||
-rw-r--r-- | TODO | 2 | ||||
-rw-r--r-- | src/basic/hmac.c | 62 | ||||
-rw-r--r-- | src/basic/hmac.h | 12 | ||||
-rw-r--r-- | src/basic/khash.c | 321 | ||||
-rw-r--r-- | src/basic/khash.h | 37 | ||||
-rw-r--r-- | src/basic/meson.build | 4 | ||||
-rw-r--r-- | src/boot/efi/meson.build | 2 | ||||
-rw-r--r-- | src/boot/efi/sha256.h | 28 | ||||
-rw-r--r-- | src/fundamental/macro-fundamental.h | 2 | ||||
-rw-r--r-- | src/fundamental/meson.build | 2 | ||||
-rw-r--r-- | src/fundamental/sha256.c (renamed from src/boot/efi/sha256.c) | 94 | ||||
-rw-r--r-- | src/fundamental/sha256.h | 32 | ||||
-rw-r--r-- | src/fundamental/string-util-fundamental.c | 8 | ||||
-rw-r--r-- | src/fundamental/string-util-fundamental.h | 4 | ||||
-rw-r--r-- | src/fundamental/type.h | 3 | ||||
-rw-r--r-- | src/libsystemd/meson.build | 3 | ||||
-rw-r--r-- | src/libsystemd/sd-id128/sd-id128.c | 43 | ||||
-rw-r--r-- | src/test/meson.build | 4 | ||||
-rw-r--r-- | src/test/test-hash.c | 76 | ||||
-rw-r--r-- | src/test/test-hmac.c | 76 | ||||
-rw-r--r-- | src/test/test-id128.c | 58 |
22 files changed, 301 insertions, 577 deletions
diff --git a/LICENSES/README.md b/LICENSES/README.md index f01049c13f..3c28de51b1 100644 --- a/LICENSES/README.md +++ b/LICENSES/README.md @@ -58,3 +58,8 @@ The following exceptions apply: **BSD-3-Clause** license. * any files under test/ without an explicit license we assume non-copyrightable (eg: computer-generated fuzzer data) + +## OpenSSL Notes + +Note that building the systemd project with OpenSSL does not affect the libsystemd.so +shared library, which is not linked with the OpenSSL library. @@ -352,11 +352,9 @@ Features: * unify on openssl (as soon as OpenSSL 3.0 is out, and the Debian license confusion is gone) - - port sd_id128_get_machine_app_specific() over from khash - port resolved over from libgcrypt (DNSSEC code) - port journald + fsprg over from libgcrypt - port importd over from libgcrypt - - when that's done: kill khash.c - when that's done: kill gnutls support in resolved * add growvol and makevol options for /etc/crypttab, similar to diff --git a/src/basic/hmac.c b/src/basic/hmac.c new file mode 100644 index 0000000000..1e4e380aaa --- /dev/null +++ b/src/basic/hmac.c @@ -0,0 +1,62 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include <assert.h> +#include <string.h> + +#include "hmac.h" +#include "sha256.h" + +#define HMAC_BLOCK_SIZE 64 +#define INNER_PADDING_BYTE 0x36 +#define OUTER_PADDING_BYTE 0x5c + +void hmac_sha256(const void *key, + size_t key_size, + const void *input, + size_t input_size, + uint8_t res[static SHA256_DIGEST_SIZE]) { + + uint8_t inner_padding[HMAC_BLOCK_SIZE] = { }; + uint8_t outer_padding[HMAC_BLOCK_SIZE] = { }; + uint8_t replacement_key[SHA256_DIGEST_SIZE]; + struct sha256_ctx hash; + + assert(key); + assert(key_size > 0); + assert(res); + + /* Implement algorithm as described by FIPS 198. */ + + /* The key needs to be block size length or less, hash it if it's longer. */ + if (key_size > HMAC_BLOCK_SIZE) { + sha256_init_ctx(&hash); + sha256_process_bytes(key, key_size, &hash); + sha256_finish_ctx(&hash, replacement_key); + key = replacement_key; + key_size = SHA256_DIGEST_SIZE; + } + + /* First, copy the key into the padding arrays. If it's shorter than + * the block size, the arrays are already initialized to 0. */ + memcpy(inner_padding, key, key_size); + memcpy(outer_padding, key, key_size); + + /* Then, XOR the provided key and any padding leftovers with the fixed + * padding bytes as defined in FIPS 198. */ + for (size_t i = 0; i < HMAC_BLOCK_SIZE; i++) { + inner_padding[i] ^= INNER_PADDING_BYTE; + outer_padding[i] ^= OUTER_PADDING_BYTE; + } + + /* First pass: hash the inner padding array and the input. */ + sha256_init_ctx(&hash); + sha256_process_bytes(inner_padding, HMAC_BLOCK_SIZE, &hash); + sha256_process_bytes(input, input_size, &hash); + sha256_finish_ctx(&hash, res); + + /* Second pass: hash the outer padding array and the result of the first pass. */ + sha256_init_ctx(&hash); + sha256_process_bytes(outer_padding, HMAC_BLOCK_SIZE, &hash); + sha256_process_bytes(res, SHA256_DIGEST_SIZE, &hash); + sha256_finish_ctx(&hash, res); +} diff --git a/src/basic/hmac.h b/src/basic/hmac.h new file mode 100644 index 0000000000..12b594c09b --- /dev/null +++ b/src/basic/hmac.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include <stdint.h> +#include <stdlib.h> + +#define SHA256_DIGEST_SIZE 32 + +/* Unoptimized implementation based on FIPS 198. 'res' has to be allocated by + * the caller. Prefer external OpenSSL functions, and use this only when + * linking to OpenSSL is not desireable (eg: libsystemd.so). */ +void hmac_sha256(const void *key, size_t key_size, const void *input, size_t input_size, uint8_t res[static SHA256_DIGEST_SIZE]); diff --git a/src/basic/khash.c b/src/basic/khash.c deleted file mode 100644 index 6a4d1dd594..0000000000 --- a/src/basic/khash.c +++ /dev/null @@ -1,321 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ - -#include <linux/if_alg.h> -#include <stdbool.h> -#include <sys/socket.h> - -#include "alloc-util.h" -#include "fd-util.h" -#include "hexdecoct.h" -#include "khash.h" -#include "macro.h" -#include "missing_socket.h" -#include "string-util.h" -#include "util.h" - -/* On current kernels the maximum digest (according to "grep digestsize /proc/crypto | sort -u") is actually 32, but - * let's add some extra room, the few wasted bytes don't really matter... */ -#define LONGEST_DIGEST 128 - -struct khash { - int fd; - char *algorithm; - uint8_t digest[LONGEST_DIGEST+1]; - size_t digest_size; - bool digest_valid; -}; - -int khash_supported(void) { - static const union { - struct sockaddr sa; - struct sockaddr_alg alg; - } sa = { - .alg.salg_family = AF_ALG, - .alg.salg_type = "hash", - .alg.salg_name = "sha256", /* a very common algorithm */ - }; - - static int cached = -1; - - if (cached < 0) { - _cleanup_close_ int fd1 = -1, fd2 = -1; - uint8_t buf[LONGEST_DIGEST+1]; - - fd1 = socket(AF_ALG, SOCK_SEQPACKET|SOCK_CLOEXEC, 0); - if (fd1 < 0) { - /* The kernel returns EAFNOSUPPORT if AF_ALG is not supported at all */ - if (IN_SET(errno, EAFNOSUPPORT, EOPNOTSUPP)) - return (cached = false); - - return -errno; - } - - if (bind(fd1, &sa.sa, sizeof(sa)) < 0) { - /* The kernel returns ENOENT if the selected algorithm is not supported at all. We use a check - * for SHA256 as a proxy for whether the whole API is supported at all. After all it's one of - * the most common hash functions, and if it isn't supported, that's ample indication that - * something is really off. */ - - if (IN_SET(errno, ENOENT, EOPNOTSUPP)) - return (cached = false); - - return -errno; - } - - fd2 = accept4(fd1, NULL, 0, SOCK_CLOEXEC); - if (fd2 < 0) { - if (errno == EOPNOTSUPP) - return (cached = false); - - return -errno; - } - - if (recv(fd2, buf, sizeof(buf), 0) < 0) { - /* On some kernels we get ENOKEY for non-keyed hash functions (such as sha256), let's refuse - * using the API in those cases, since the kernel is - * broken. https://github.com/systemd/systemd/issues/8278 */ - - if (IN_SET(errno, ENOKEY, EOPNOTSUPP)) - return (cached = false); - } - - cached = true; - } - - return cached; -} - -int khash_new_with_key(khash **ret, const char *algorithm, const void *key, size_t key_size) { - union { - struct sockaddr sa; - struct sockaddr_alg alg; - } sa = { - .alg.salg_family = AF_ALG, - .alg.salg_type = "hash", - }; - - _cleanup_(khash_unrefp) khash *h = NULL; - _cleanup_close_ int fd = -1; - int supported; - ssize_t n; - - assert(ret); - assert(key || key_size == 0); - - /* Filter out an empty algorithm early, as we do not support an algorithm by that name. */ - if (isempty(algorithm)) - return -EINVAL; - - /* Overly long hash algorithm names we definitely do not support */ - if (strlen(algorithm) >= sizeof(sa.alg.salg_name)) - return -EOPNOTSUPP; - - supported = khash_supported(); - if (supported < 0) - return supported; - if (supported == 0) - return -EOPNOTSUPP; - - fd = socket(AF_ALG, SOCK_SEQPACKET|SOCK_CLOEXEC, 0); - if (fd < 0) - return -errno; - - strcpy((char*) sa.alg.salg_name, algorithm); - if (bind(fd, &sa.sa, sizeof(sa)) < 0) { - if (errno == ENOENT) - return -EOPNOTSUPP; - return -errno; - } - - if (key) { - if (setsockopt(fd, SOL_ALG, ALG_SET_KEY, key, key_size) < 0) - return -errno; - } - - h = new0(khash, 1); - if (!h) - return -ENOMEM; - - h->fd = accept4(fd, NULL, 0, SOCK_CLOEXEC); - if (h->fd < 0) - return -errno; - - h->algorithm = strdup(algorithm); - if (!h->algorithm) - return -ENOMEM; - - /* Temporary fix for rc kernel bug: https://bugzilla.redhat.com/show_bug.cgi?id=1395896 */ - (void) send(h->fd, NULL, 0, 0); - - /* Figure out the digest size */ - n = recv(h->fd, h->digest, sizeof(h->digest), 0); - if (n < 0) - return -errno; - if (n >= LONGEST_DIGEST) /* longer than what we expected? If so, we don't support this */ - return -EOPNOTSUPP; - - h->digest_size = (size_t) n; - h->digest_valid = true; - - /* Temporary fix for rc kernel bug: https://bugzilla.redhat.com/show_bug.cgi?id=1395896 */ - (void) send(h->fd, NULL, 0, 0); - - *ret = TAKE_PTR(h); - - return 0; -} - -int khash_new(khash **ret, const char *algorithm) { - return khash_new_with_key(ret, algorithm, NULL, 0); -} - -khash* khash_unref(khash *h) { - if (!h) - return NULL; - - safe_close(h->fd); - free(h->algorithm); - return mfree(h); -} - -int khash_dup(khash *h, khash **ret) { - _cleanup_(khash_unrefp) khash *copy = NULL; - - assert(h); - assert(ret); - - copy = newdup(khash, h, 1); - if (!copy) - return -ENOMEM; - - copy->fd = -1; - copy->algorithm = strdup(h->algorithm); - if (!copy->algorithm) - return -ENOMEM; - - copy->fd = accept4(h->fd, NULL, 0, SOCK_CLOEXEC); - if (copy->fd < 0) - return -errno; - - *ret = TAKE_PTR(copy); - - return 0; -} - -const char *khash_get_algorithm(khash *h) { - assert(h); - - return h->algorithm; -} - -size_t khash_get_size(khash *h) { - assert(h); - - return h->digest_size; -} - -int khash_reset(khash *h) { - ssize_t n; - - assert(h); - - n = send(h->fd, NULL, 0, 0); - if (n < 0) - return -errno; - - h->digest_valid = false; - - return 0; -} - -int khash_put(khash *h, const void *buffer, size_t size) { - ssize_t n; - - assert(h); - assert(buffer || size == 0); - - if (size <= 0) - return 0; - - n = send(h->fd, buffer, size, MSG_MORE); - if (n < 0) - return -errno; - - h->digest_valid = false; - - return 0; -} - -int khash_put_iovec(khash *h, const struct iovec *iovec, size_t n) { - struct msghdr mh = { - .msg_iov = (struct iovec*) iovec, - .msg_iovlen = n, - }; - ssize_t k; - - assert(h); - assert(iovec || n == 0); - - if (n <= 0) - return 0; - - k = sendmsg(h->fd, &mh, MSG_MORE); - if (k < 0) - return -errno; - - h->digest_valid = false; - - return 0; -} - -static int retrieve_digest(khash *h) { - ssize_t n; - - assert(h); - - if (h->digest_valid) - return 0; - - n = recv(h->fd, h->digest, h->digest_size, 0); - if (n < 0) - return n; - if ((size_t) n != h->digest_size) /* digest size changed? */ - return -EIO; - - h->digest_valid = true; - - return 0; -} - -int khash_digest_data(khash *h, const void **ret) { - int r; - - assert(h); - assert(ret); - - r = retrieve_digest(h); - if (r < 0) - return r; - - *ret = h->digest; - return 0; -} - -int khash_digest_string(khash *h, char **ret) { - int r; - char *p; - - assert(h); - assert(ret); - - r = retrieve_digest(h); - if (r < 0) - return r; - - p = hexmem(h->digest, h->digest_size); - if (!p) - return -ENOMEM; - - *ret = p; - return 0; -} diff --git a/src/basic/khash.h b/src/basic/khash.h deleted file mode 100644 index a343d306e9..0000000000 --- a/src/basic/khash.h +++ /dev/null @@ -1,37 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -#pragma once - -#include <inttypes.h> -#include <sys/types.h> -#include <sys/uio.h> - -#include "macro.h" - -typedef struct khash khash; - -int khash_supported(void); - -/* For plain hash functions. Hash functions commonly supported on today's kernels are: crc32c, crct10dif, crc32, - * sha224, sha256, sha512, sha384, sha1, md5, md4, sha3-224, sha3-256, sha3-384, sha3-512, and more. */ -int khash_new(khash **ret, const char *algorithm); - -/* For keyed hash functions. Hash functions commonly supported on today's kernels are: hmac(sha256), cmac(aes), - * cmac(des3_ede), hmac(sha3-512), hmac(sha3-384), hmac(sha3-256), hmac(sha3-224), hmac(rmd160), hmac(rmd128), - * hmac(sha224), hmac(sha512), hmac(sha384), hmac(sha1), hmac(md5), and more. */ -int khash_new_with_key(khash **ret, const char *algorithm, const void *key, size_t key_size); - -int khash_dup(khash *h, khash **ret); -khash* khash_unref(khash *h); - -const char *khash_get_algorithm(khash *h); -size_t khash_get_size(khash *h); - -int khash_reset(khash *h); - -int khash_put(khash *h, const void *buffer, size_t size); -int khash_put_iovec(khash *h, const struct iovec *iovec, size_t n); - -int khash_digest_data(khash *h, const void **ret); -int khash_digest_string(khash *h, char **ret); - -DEFINE_TRIVIAL_CLEANUP_FUNC(khash*, khash_unref); diff --git a/src/basic/meson.build b/src/basic/meson.build index adb7b666c6..cf97f6de1d 100644 --- a/src/basic/meson.build +++ b/src/basic/meson.build @@ -72,6 +72,8 @@ basic_sources = files(''' hashmap.h hexdecoct.c hexdecoct.h + hmac.c + hmac.h hostname-util.c hostname-util.h in-addr-util.c @@ -80,8 +82,6 @@ basic_sources = files(''' inotify-util.h io-util.c io-util.h - khash.c - khash.h limits-util.c limits-util.h linux/btrfs.h diff --git a/src/boot/efi/meson.build b/src/boot/efi/meson.build index fef8572c6a..81b750d5d3 100644 --- a/src/boot/efi/meson.build +++ b/src/boot/efi/meson.build @@ -12,7 +12,6 @@ efi_headers = files(''' missing_efi.h pe.h random-seed.h - sha256.h shim.h splash.h util.h @@ -34,7 +33,6 @@ systemd_boot_sources = ''' devicetree.c drivers.c random-seed.c - sha256.c shim.c '''.split() diff --git a/src/boot/efi/sha256.h b/src/boot/efi/sha256.h deleted file mode 100644 index 464be59c25..0000000000 --- a/src/boot/efi/sha256.h +++ /dev/null @@ -1,28 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -#pragma once - -#include <efi.h> -#include <efilib.h> - -struct sha256_ctx { - UINT32 H[8]; - - union { - UINT64 total64; -#define TOTAL64_low (1 - (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) -#define TOTAL64_high (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) - UINT32 total[2]; - }; - - UINT32 buflen; - - union { - UINT8 buffer[128]; /* NB: always correctly aligned for UINT32. */ - UINT32 buffer32[32]; - UINT64 buffer64[16]; - }; -}; - -void sha256_init_ctx(struct sha256_ctx *ctx); -void *sha256_finish_ctx(struct sha256_ctx *ctx, VOID *resbuf); -void sha256_process_bytes(const void *buffer, UINTN len, struct sha256_ctx *ctx); diff --git a/src/fundamental/macro-fundamental.h b/src/fundamental/macro-fundamental.h index 20d8dabf29..7fa4b85be7 100644 --- a/src/fundamental/macro-fundamental.h +++ b/src/fundamental/macro-fundamental.h @@ -59,6 +59,8 @@ #define assert(expr) ({ _likely_(expr) ? VOID_0 : efi_assert(#expr, __FILE__, __LINE__, __PRETTY_FUNCTION__); }) #define assert_not_reached() efi_assert("Code should not be reached", __FILE__, __LINE__, __PRETTY_FUNCTION__) #endif + + #define memcpy(a, b, c) CopyMem((a), (b), (c)) #endif #if defined(static_assert) diff --git a/src/fundamental/meson.build b/src/fundamental/meson.build index 3c43081cf6..3aa9fab8cb 100644 --- a/src/fundamental/meson.build +++ b/src/fundamental/meson.build @@ -6,10 +6,12 @@ fundamental_headers = files( 'efi-loader-features.h', 'macro-fundamental.h', 'string-util-fundamental.h', + 'sha256.h', 'type.h') sources = ''' string-util-fundamental.c + sha256.c '''.split() # for sd-boot diff --git a/src/boot/efi/sha256.c b/src/fundamental/sha256.c index d2e267eeff..0577a24920 100644 --- a/src/boot/efi/sha256.c +++ b/src/fundamental/sha256.c @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ -/* Stolen from glibc and converted to UEFI style. In glibc it comes with the following copyright blurb: */ +/* Stolen from glibc and converted to our style. In glibc it comes with the following copyright blurb: */ /* Functions to compute SHA256 message digest of files or memory blocks. according to the definition of SHA256 in FIPS 180-2. @@ -23,6 +23,10 @@ /* Written by Ulrich Drepper <drepper@redhat.com>, 2007. */ +#ifndef SD_BOOT +#include <string.h> +#endif + #include "macro-fundamental.h" #include "sha256.h" @@ -45,12 +49,12 @@ /* This array contains the bytes used to pad the buffer to the next 64-byte boundary. (FIPS 180-2:5.1.1) */ -static const UINT8 fillbuf[64] = { +static const uint8_t fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ }; /* Constants for SHA256 from FIPS 180-2:4.2.2. */ -static const UINT32 K[64] = { +static const uint32_t K[64] = { 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, @@ -69,7 +73,7 @@ static const UINT32 K[64] = { 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 }; -static void sha256_process_block(const void *, UINTN, struct sha256_ctx *); +static void sha256_process_block(const void *, size_t, struct sha256_ctx *); /* Initialize structure containing state of computation. (FIPS 180-2:5.3.2) */ @@ -96,8 +100,8 @@ void sha256_init_ctx(struct sha256_ctx *ctx) { aligned for a 32 bits value. */ void *sha256_finish_ctx(struct sha256_ctx *ctx, void *resbuf) { /* Take yet unprocessed bytes into account. */ - UINT32 bytes = ctx->buflen; - UINTN pad; + uint32_t bytes = ctx->buflen; + size_t pad; assert(ctx); assert(resbuf); @@ -106,7 +110,7 @@ void *sha256_finish_ctx(struct sha256_ctx *ctx, void *resbuf) { ctx->total64 += bytes; pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes; - CopyMem(&ctx->buffer[bytes], fillbuf, pad); + memcpy(&ctx->buffer[bytes], fillbuf, pad); /* Put the 64-bit file length in *bits* at the end of the buffer. */ ctx->buffer32[(bytes + pad + 4) / 4] = SWAP(ctx->total[TOTAL64_low] << 3); @@ -117,13 +121,13 @@ void *sha256_finish_ctx(struct sha256_ctx *ctx, void *resbuf) { sha256_process_block(ctx->buffer, bytes + pad + 8, ctx); /* Put result from CTX in first 32 bytes following RESBUF. */ - for (UINTN i = 0; i < 8; ++i) - ((UINT32 *) resbuf)[i] = SWAP(ctx->H[i]); + for (size_t i = 0; i < 8; ++i) + ((uint32_t *) resbuf)[i] = SWAP(ctx->H[i]); return resbuf; } -void sha256_process_bytes(const void *buffer, UINTN len, struct sha256_ctx *ctx) { +void sha256_process_bytes(const void *buffer, size_t len, struct sha256_ctx *ctx) { assert(buffer); assert(ctx); @@ -131,10 +135,10 @@ void sha256_process_bytes(const void *buffer, UINTN len, struct sha256_ctx *ctx) both inputs first. */ if (ctx->buflen != 0) { - UINTN left_over = ctx->buflen; - UINTN add = 128 - left_over > len ? len : 128 - left_over; + size_t left_over = ctx->buflen; + size_t add = 128 - left_over > len ? len : 128 - left_over; - CopyMem(&ctx->buffer[left_over], buffer, add); + memcpy(&ctx->buffer[left_over], buffer, add); ctx->buflen += add; if (ctx->buflen > 64) { @@ -142,7 +146,7 @@ void sha256_process_bytes(const void *buffer, UINTN len, struct sha256_ctx *ctx) ctx->buflen &= 63; /* The regions in the following copy operation cannot overlap. */ - CopyMem(ctx->buffer, &ctx->buffer[(left_over + add) & ~63], + memcpy(ctx->buffer, &ctx->buffer[(left_over + add) & ~63], ctx->buflen); } @@ -159,13 +163,13 @@ void sha256_process_bytes(const void *buffer, UINTN len, struct sha256_ctx *ctx) /* To check alignment gcc has an appropriate operator. Other compilers don't. */ # if __GNUC__ >= 2 -# define UNALIGNED_P(p) (((UINTN) p) % __alignof__(UINT32) != 0) +# define UNALIGNED_P(p) (((size_t) p) % __alignof__(uint32_t) != 0) # else -# define UNALIGNED_P(p) (((UINTN) p) % sizeof(UINT32) != 0) +# define UNALIGNED_P(p) (((size_t) p) % sizeof(uint32_t) != 0) # endif if (UNALIGNED_P(buffer)) while (len > 64) { - CopyMem(ctx->buffer, buffer, 64); + memcpy(ctx->buffer, buffer, 64); sha256_process_block(ctx->buffer, 64, ctx); buffer = (const char *) buffer + 64; len -= 64; @@ -181,14 +185,14 @@ void sha256_process_bytes(const void *buffer, UINTN len, struct sha256_ctx *ctx) /* Move remaining bytes into internal buffer. */ if (len > 0) { - UINTN left_over = ctx->buflen; + size_t left_over = ctx->buflen; - CopyMem(&ctx->buffer[left_over], buffer, len); + memcpy(&ctx->buffer[left_over], buffer, len); left_over += len; if (left_over >= 64) { sha256_process_block(ctx->buffer, 64, ctx); left_over -= 64; - CopyMem(ctx->buffer, &ctx->buffer[64], left_over); + memcpy(ctx->buffer, &ctx->buffer[64], left_over); } ctx->buflen = left_over; } @@ -197,21 +201,21 @@ void sha256_process_bytes(const void *buffer, UINTN len, struct sha256_ctx *ctx) /* Process LEN bytes of BUFFER, accumulating context into CTX. It is assumed that LEN % 64 == 0. */ -static void sha256_process_block(const void *buffer, UINTN len, struct sha256_ctx *ctx) { - const UINT32 *words = buffer; - UINTN nwords = len / sizeof(UINT32); +static void sha256_process_block(const void *buffer, size_t len, struct sha256_ctx *ctx) { + const uint32_t *words = buffer; + size_t nwords = len / sizeof(uint32_t); assert(buffer); assert(ctx); - UINT32 a = ctx->H[0]; - UINT32 b = ctx->H[1]; - UINT32 c = ctx->H[2]; - UINT32 d = ctx->H[3]; - UINT32 e = ctx->H[4]; - UINT32 f = ctx->H[5]; - UINT32 g = ctx->H[6]; - UINT32 h = ctx->H[7]; + uint32_t a = ctx->H[0]; + uint32_t b = ctx->H[1]; + uint32_t c = ctx->H[2]; + uint32_t d = ctx->H[3]; + uint32_t e = ctx->H[4]; + uint32_t f = ctx->H[5]; + uint32_t g = ctx->H[6]; + uint32_t h = ctx->H[7]; /* First increment the byte count. FIPS 180-2 specifies the possible length of the file up to 2^64 bits. Here we only compute the @@ -221,15 +225,15 @@ static void sha256_process_block(const void *buffer, UINTN len, struct sha256_ct /* Process all bytes in the buffer with 64 bytes in each round of the loop. */ while (nwords > 0) { - UINT32 W[64]; - UINT32 a_save = a; - UINT32 b_save = b; - UINT32 c_save = c; - UINT32 d_save = d; - UINT32 e_save = e; - UINT32 f_save = f; - UINT32 g_save = g; - UINT32 h_save = h; + uint32_t W[64]; + uint32_t a_save = a; + uint32_t b_save = b; + uint32_t c_save = c; + uint32_t d_save = d; + uint32_t e_save = e; + uint32_t f_save = f; + uint32_t g_save = g; + uint32_t h_save = h; /* Operators defined in FIPS 180-2:4.1.2. */ #define Ch(x, y, z) ((x & y) ^ (~x & z)) @@ -244,17 +248,17 @@ static void sha256_process_block(const void *buffer, UINTN len, struct sha256_ct #define CYCLIC(w, s) ((w >> s) | (w << (32 - s))) /* Compute the message schedule according to FIPS 180-2:6.2.2 step 2. */ - for (UINTN t = 0; t < 16; ++t) { + for (size_t t = 0; t < 16; ++t) { W[t] = SWAP (*words); ++words; } - for (UINTN t = 16; t < 64; ++t) + for (size_t t = 16; t < 64; ++t) W[t] = R1 (W[t - 2]) + W[t - 7] + R0 (W[t - 15]) + W[t - 16]; /* The actual computation according to FIPS 180-2:6.2.2 step 3. */ - for (UINTN t = 0; t < 64; ++t) { - UINT32 T1 = h + S1 (e) + Ch (e, f, g) + K[t] + W[t]; - UINT32 T2 = S0 (a) + Maj (a, b, c); + for (size_t t = 0; t < 64; ++t) { + uint32_t T1 = h + S1 (e) + Ch (e, f, g) + K[t] + W[t]; + uint32_t T2 = S0 (a) + Maj (a, b, c); h = g; g = f; f = e; diff --git a/src/fundamental/sha256.h b/src/fundamental/sha256.h new file mode 100644 index 0000000000..9fc090b4e0 --- /dev/null +++ b/src/fundamental/sha256.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#ifdef SD_BOOT +#include <efi.h> +#include <efilib.h> +#endif + +#include "type.h" + +struct sha256_ctx { + uint32_t H[8]; + + union { + uint64_t total64; +#define TOTAL64_low (1 - (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) +#define TOTAL64_high (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) + uint32_t total[2]; + }; + + uint32_t buflen; + + union { + uint8_t buffer[128]; /* NB: always correctly aligned for UINT32. */ + uint32_t buffer32[32]; + uint64_t buffer64[16]; + }; +}; + +void sha256_init_ctx(struct sha256_ctx *ctx); +void *sha256_finish_ctx(struct sha256_ctx *ctx, void *resbuf); +void sha256_process_bytes(const void *buffer, size_t len, struct sha256_ctx *ctx); diff --git a/src/fundamental/string-util-fundamental.c b/src/fundamental/string-util-fundamental.c index 383e390577..101d3f7196 100644 --- a/src/fundamental/string-util-fundamental.c +++ b/src/fundamental/string-util-fundamental.c @@ -8,7 +8,7 @@ #include "string-util-fundamental.h" sd_char *startswith(const sd_char *s, const sd_char *prefix) { - sd_size_t l; + size_t l; assert(s); assert(prefix); @@ -22,7 +22,7 @@ sd_char *startswith(const sd_char *s, const sd_char *prefix) { #ifndef SD_BOOT sd_char *startswith_no_case(const sd_char *s, const sd_char *prefix) { - sd_size_t l; + size_t l; assert(s); assert(prefix); @@ -36,7 +36,7 @@ sd_char *startswith_no_case(const sd_char *s, const sd_char *prefix) { #endif sd_char* endswith(const sd_char *s, const sd_char *postfix) { - sd_size_t sl, pl; + size_t sl, pl; assert(s); assert(postfix); @@ -57,7 +57,7 @@ sd_char* endswith(const sd_char *s, const sd_char *postfix) { } sd_char* endswith_no_case(const sd_char *s, const sd_char *postfix) { - sd_size_t sl, pl; + size_t sl, pl; assert(s); assert(postfix); diff --git a/src/fundamental/string-util-fundamental.h b/src/fundamental/string-util-fundamental.h index 7455c05492..dc0c1202be 100644 --- a/src/fundamental/string-util-fundamental.h +++ b/src/fundamental/string-util-fundamental.h @@ -68,10 +68,10 @@ static inline const sd_char *yes_no(sd_bool b) { sd_int strverscmp_improved(const sd_char *a, const sd_char *b); /* Like startswith(), but operates on arbitrary memory blocks */ -static inline void *memory_startswith(const void *p, sd_size_t sz, const sd_char *token) { +static inline void *memory_startswith(const void *p, size_t sz, const sd_char *token) { assert(token); - sd_size_t n = strlen(token) * sizeof(sd_char); + size_t n = strlen(token) * sizeof(sd_char); if (sz < n) return NULL; diff --git a/src/fundamental/type.h b/src/fundamental/type.h index f645d2de7f..2a9a114bbc 100644 --- a/src/fundamental/type.h +++ b/src/fundamental/type.h @@ -7,7 +7,7 @@ typedef BOOLEAN sd_bool; typedef CHAR16 sd_char; typedef INTN sd_int; -typedef UINTN sd_size_t; +typedef UINTN size_t; #define true TRUE #define false FALSE @@ -18,5 +18,4 @@ typedef UINTN sd_size_t; typedef bool sd_bool; typedef char sd_char; typedef int sd_int; -typedef size_t sd_size_t; #endif diff --git a/src/libsystemd/meson.build b/src/libsystemd/meson.build index 8ec871f6a4..02b2cd64b2 100644 --- a/src/libsystemd/meson.build +++ b/src/libsystemd/meson.build @@ -170,8 +170,7 @@ libsystemd_static = static_library( include_directories : libsystemd_includes, link_with : libbasic, dependencies : [threads, - librt, - libopenssl], + librt], c_args : libsystemd_c_args) libsystemd_sym = files('libsystemd.sym') diff --git a/src/libsystemd/sd-id128/sd-id128.c b/src/libsystemd/sd-id128/sd-id128.c index 28ae10a198..992b19130e 100644 --- a/src/libsystemd/sd-id128/sd-id128.c +++ b/src/libsystemd/sd-id128/sd-id128.c @@ -4,21 +4,14 @@ #include <fcntl.h> #include <unistd.h> -#if HAVE_OPENSSL -#include <openssl/hmac.h> -#include <openssl/sha.h> -#endif - #include "sd-id128.h" #include "alloc-util.h" #include "fd-util.h" #include "hexdecoct.h" +#include "hmac.h" #include "id128-util.h" #include "io-util.h" -#if !HAVE_OPENSSL -#include "khash.h" -#endif #include "macro.h" #include "missing_syscall.h" #include "random-util.h" @@ -278,43 +271,15 @@ _public_ int sd_id128_randomize(sd_id128_t *ret) { } static int get_app_specific(sd_id128_t base, sd_id128_t app_id, sd_id128_t *ret) { + uint8_t hmac[SHA256_DIGEST_SIZE]; sd_id128_t result; assert(ret); -#if HAVE_OPENSSL - /* We prefer doing this in-process, since we this means we are not dependent on kernel configuration, - * and this also works in locked down container environments. But some distros don't like OpenSSL's - * license and its (in-) compatibility with GPL2, hence also support khash */ - uint8_t md[256/8]; - if (!HMAC(EVP_sha256(), - &base, sizeof(base), - (const unsigned char*) &app_id, sizeof(app_id), - md, NULL)) - return -ENOTRECOVERABLE; + hmac_sha256(&base, sizeof(base), &app_id, sizeof(app_id), hmac); /* Take only the first half. */ - memcpy(&result, md, MIN(sizeof(md), sizeof(result))); -#else - _cleanup_(khash_unrefp) khash *h = NULL; - const void *p; - int r; - - r = khash_new_with_key(&h, "hmac(sha256)", &base, sizeof(base)); - if (r < 0) - return r; - - r = khash_put(h, &app_id, sizeof(app_id)); - if (r < 0) - return r; - - r = khash_digest_data(h, &p); - if (r < 0) - return r; - - /* We chop off the trailing 16 bytes */ - memcpy(&result, p, MIN(khash_get_size(h), sizeof(result))); -#endif + memcpy(&result, hmac, MIN(sizeof(hmac), sizeof(result))); *ret = id128_make_v4_uuid(result); return 0; diff --git a/src/test/meson.build b/src/test/meson.build index fea7f107fd..292b6329e4 100644 --- a/src/test/meson.build +++ b/src/test/meson.build @@ -592,8 +592,6 @@ tests += [ [['src/test/test-id128.c']], - [['src/test/test-hash.c']], - [['src/test/test-gcrypt-util.c'], [], [], [], 'HAVE_GCRYPT'], @@ -629,6 +627,8 @@ tests += [ [['src/test/test-nscd-flush.c'], [], [], [], 'ENABLE_NSCD', 'manual'], + + [['src/test/test-hmac.c']], ] ############################################################ diff --git a/src/test/test-hash.c b/src/test/test-hash.c deleted file mode 100644 index 270fcd0df4..0000000000 --- a/src/test/test-hash.c +++ /dev/null @@ -1,76 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ - -#include <errno.h> -#include <stdio.h> - -#include "alloc-util.h" -#include "log.h" -#include "string-util.h" -#include "khash.h" -#include "tests.h" - -int main(int argc, char *argv[]) { - _cleanup_(khash_unrefp) khash *h = NULL, *copy = NULL; - _cleanup_free_ char *s = NULL; - int r; - - test_setup_logging(LOG_DEBUG); - - assert_se(khash_new(&h, NULL) == -EINVAL); - assert_se(khash_new(&h, "") == -EINVAL); - - r = khash_supported(); - assert_se(r >= 0); - if (r == 0) - return log_tests_skipped("khash not supported on this kernel"); - - assert_se(khash_new(&h, "foobar") == -EOPNOTSUPP); /* undefined hash function */ - - assert_se(khash_new(&h, "sha256") >= 0); - assert_se(khash_get_size(h) == 32); - assert_se(streq(khash_get_algorithm(h), "sha256")); - - assert_se(khash_digest_string(h, &s) >= 0); - assert_se(streq(s, "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")); - s = mfree(s); - - assert_se(khash_put(h, "foobar", 6) >= 0); - assert_se(khash_digest_string(h, &s) >= 0); - assert_se(streq(s, "c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2")); - s = mfree(s); - - assert_se(khash_put(h, "piep", 4) >= 0); - assert_se(khash_digest_string(h, &s) >= 0); - assert_se(streq(s, "f114d872b5ea075d3be9040d0b7a429514b3f9324a8e8e3dc3fb24c34ee56bea")); - s = mfree(s); - - assert_se(khash_put(h, "foo", 3) >= 0); - assert_se(khash_dup(h, ©) >= 0); - - assert_se(khash_put(h, "bar", 3) >= 0); - assert_se(khash_put(copy, "bar", 3) >= 0); - - assert_se(khash_digest_string(h, &s) >= 0); - assert_se(streq(s, "c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2")); - s = mfree(s); - - assert_se(khash_digest_string(copy, &s) >= 0); - assert_se(streq(s, "c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2")); - s = mfree(s); - - h = khash_unref(h); - - assert_se(khash_new_with_key(&h, "hmac(sha256)", "quux", 4) >= 0); - assert_se(khash_get_size(h) == 32); - assert_se(streq(khash_get_algorithm(h), "hmac(sha256)")); - - assert_se(khash_digest_string(h, &s) >= 0); - assert_se(streq(s, "abed9f8218ab473f77218a6a7d39abf1d21fa46d0700c4898e330ba88309d5ae")); - s = mfree(s); - - assert_se(khash_put(h, "foobar", 6) >= 0); - assert_se(khash_digest_string(h, &s) >= 0); - assert_se(streq(s, "33f6c70a60db66007d5325d5d1dea37c371354e5b83347a59ad339ce9f4ba3dc")); - - return 0; -} diff --git a/src/test/test-hmac.c b/src/test/test-hmac.c new file mode 100644 index 0000000000..5c73eca110 --- /dev/null +++ b/src/test/test-hmac.c @@ -0,0 +1,76 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "hexdecoct.h" +#include "hmac.h" +#include "string-util.h" +#include "tests.h" + +static void hmac_sha256_by_string(const char *key, const char *value, uint8_t res[static SHA256_DIGEST_SIZE]) { + hmac_sha256(key, strlen(key), value, strlen(value), res); +} + +static void test_hmac(void) { + uint8_t result[SHA256_DIGEST_SIZE]; + char *hex_result = NULL; + + log_info("/* %s */", __func__); + + /* Results compared with output of 'echo -n "<input>" | openssl dgst -sha256 -hmac "<key>"' */ + + hmac_sha256_by_string("waldo", + "", + result); + hex_result = hexmem(result, sizeof(result)); + assert_se(streq_ptr(hex_result, "cadd5e42114351181f3abff477641d88efb57d2b5641a1e5c6d623363a6d3bad")); + hex_result = mfree(hex_result); + + hmac_sha256_by_string("waldo", + "baldohaldo", + result); + hex_result = hexmem(result, sizeof(result)); + assert_se(streq_ptr(hex_result, "c47ad5031ba21605e52c6ca68090d66a2dd5ccf84efa4bace15361a8cba63cda")); + hex_result = mfree(hex_result); + + hmac_sha256_by_string("waldo", + "baldo haldo", + result); + hex_result = hexmem(result, sizeof(result)); + assert_se(streq_ptr(hex_result, "4e8974ad6c08b98cc2519cd1e27aa7195769fcf86db1dd7ceaab4d44c490ad69")); + hex_result = mfree(hex_result); + + hmac_sha256_by_string("waldo", + "baldo 4e8974ad6c08b98cc2519cd1e27aa7195769fcf86db1dd7ceaab4d44c490ad69 haldo", + result); + hex_result = hexmem(result, sizeof(result)); + assert_se(streq_ptr(hex_result, "039f3df430b19753ffb493e5b90708f75c5210b63c6bcbef3374eb3f0a3f97f7")); + hex_result = mfree(hex_result); + + hmac_sha256_by_string("4e8974ad6c08b98cc2519cd1e27aa7195769fcf86db1dd7ceaab4d44c490ad69", + "baldo haldo", + result); + hex_result = hexmem(result, sizeof(result)); + assert_se(streq_ptr(hex_result, "c4cfaf48077cbb0bbd177a09e59ec4c248f4ca771503410f5b54b98d88d2f47b")); + hex_result = mfree(hex_result); + + hmac_sha256_by_string("4e8974ad6c08b98cc2519cd1e27aa7195769fcf86db1dd7ceaab4d44c490ad69", + "supercalifragilisticexpialidocious", + result); + hex_result = hexmem(result, sizeof(result)); + assert_se(streq_ptr(hex_result, "2c059e7a63c4c3b23f47966a65fd2f8a2f5d7161e2e90d78ff68866b5c375cb7")); + hex_result = mfree(hex_result); + + hmac_sha256_by_string("4e8974ad6c08b98cc2519cd1e27aa7195769fcf86db1dd7ceaab4d44c490ad69c47ad5031ba21605e52c6ca68090d66a2dd5ccf84efa4bace15361a8cba63cda", + "supercalifragilisticexpialidocious", + result); + hex_result = hexmem(result, sizeof(result)); + assert_se(streq_ptr(hex_result, "1dd1d1d45b9d9f9673dc9983c968c46ff3168e03cfeb4156a219eba1af4cff5f")); + hex_result = mfree(hex_result); +} + +int main(int argc, char **argv) { + test_setup_logging(LOG_INFO); + + test_hmac(); + + return 0; +} diff --git a/src/test/test-id128.c b/src/test/test-id128.c index a61b35b9a3..79dc7de159 100644 --- a/src/test/test-id128.c +++ b/src/test/test-id128.c @@ -12,19 +12,20 @@ #include "id128-util.h" #include "macro.h" #include "string-util.h" +#include "tests.h" #include "tmpfile-util.h" -#include "util.h" #define ID128_WALDI SD_ID128_MAKE(01, 02, 03, 04, 05, 06, 07, 08, 09, 0a, 0b, 0c, 0d, 0e, 0f, 10) #define STR_WALDI "0102030405060708090a0b0c0d0e0f10" #define UUID_WALDI "01020304-0506-0708-090a-0b0c0d0e0f10" -int main(int argc, char *argv[]) { +static void test_id128(void) { sd_id128_t id, id2; char t[SD_ID128_STRING_MAX], q[ID128_UUID_STRING_MAX]; _cleanup_free_ char *b = NULL; _cleanup_close_ int fd = -1; - int r; + + log_info("/* %s */", __func__); assert_se(sd_id128_randomize(&id) == 0); printf("random: %s\n", sd_id128_to_string(id, t)); @@ -146,16 +147,18 @@ int main(int argc, char *argv[]) { assert_se(id128_read_fd(fd, ID128_UUID, &id2) >= 0); assert_se(sd_id128_equal(id, id2)); - r = sd_id128_get_machine_app_specific(SD_ID128_MAKE(f0,3d,aa,eb,1c,33,4b,43,a7,32,17,29,44,bf,77,2e), &id); - if (r == -EOPNOTSUPP) - log_info("khash not supported on this kernel, skipping sd_id128_get_machine_app_specific() checks"); - else { - assert_se(r >= 0); - assert_se(sd_id128_get_machine_app_specific(SD_ID128_MAKE(f0,3d,aa,eb,1c,33,4b,43,a7,32,17,29,44,bf,77,2e), &id2) >= 0); - assert_se(sd_id128_equal(id, id2)); - assert_se(sd_id128_get_machine_app_specific(SD_ID128_MAKE(51,df,0b,4b,c3,b0,4c,97,80,e2,99,b9,8c,a3,73,b8), &id2) >= 0); - assert_se(!sd_id128_equal(id, id2)); - } + assert_se(sd_id128_get_machine_app_specific(SD_ID128_MAKE(f0,3d,aa,eb,1c,33,4b,43,a7,32,17,29,44,bf,77,2e), &id) >= 0); + assert_se(sd_id128_get_machine_app_specific(SD_ID128_MAKE(f0,3d,aa,eb,1c,33,4b,43,a7,32,17,29,44,bf,77,2e), &id2) >= 0); + assert_se(sd_id128_equal(id, id2)); + assert_se(sd_id128_get_machine_app_specific(SD_ID128_MAKE(51,df,0b,4b,c3,b0,4c,97,80,e2,99,b9,8c,a3,73,b8), &id2) >= 0); + assert_se(!sd_id128_equal(id, id2)); +} + +static void test_sd_id128_get_invocation(void) { + sd_id128_t id; + int r; + + log_info("/* %s */", __func__); /* Query the invocation ID */ r = sd_id128_get_invocation(&id); @@ -163,6 +166,35 @@ int main(int argc, char *argv[]) { log_warning_errno(r, "Failed to get invocation ID, ignoring: %m"); else log_info("Invocation ID: " SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(id)); +} + +static void benchmark_sd_id128_get_machine_app_specific(void) { + unsigned iterations = slow_tests_enabled() ? 1000000 : 1000; + usec_t t, q; + + log_info("/* %s (%u iterations) */", __func__, iterations); + + sd_id128_t id = ID128_WALDI, id2; + + t = now(CLOCK_MONOTONIC); + + for (unsigned i = 0; i < iterations; i++) { + id.qwords[1] = i; + + assert_se(sd_id128_get_machine_app_specific(id, &id2) >= 0); + } + + q = now(CLOCK_MONOTONIC) - t; + + log_info("%lf µs each\n", (double) q / iterations); +} + +int main(int argc, char *argv[]) { + test_setup_logging(LOG_INFO); + + test_id128(); + test_sd_id128_get_invocation(); + benchmark_sd_id128_get_machine_app_specific(); return 0; } |