1
1
mirror of https://github.com/systemd/systemd-stable.git synced 2025-03-08 20:58:20 +03:00

Merge pull request #20915 from bluca/libsystemd_openssl

libsystemd/sd-id128: use only internal hmac, remove khash/OpenSSL support
This commit is contained in:
Luca Boccassi 2021-10-09 18:37:59 +01:00 committed by GitHub
commit ccf609c88c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 301 additions and 577 deletions

View File

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

2
TODO
View File

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

62
src/basic/hmac.c Normal file
View File

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

12
src/basic/hmac.h Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

32
src/fundamental/sha256.h Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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, &copy) >= 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;
}

76
src/test/test-hmac.c Normal file
View File

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

View File

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