systemd/0603-openssl-add-openssl_di...

180 lines
8.3 KiB
Diff

From fe351e0c111c98e1ad317df05b87705a233c46d6 Mon Sep 17 00:00:00 2001
From: Dan Streetman <ddstreet@ieee.org>
Date: Wed, 5 Jul 2023 12:28:39 -0400
Subject: [PATCH] openssl: add openssl_digest_many()
Add function to perform openssl digest calculation on multiple buffers.
(cherry picked from commit bed4831ce227a59d40b3712a3b1deee9fe0440f5)
Related: RHEL-16182
---
src/shared/openssl-util.c | 58 +++++++++++++++++++++++++++++++++++++
src/shared/openssl-util.h | 7 +++++
src/test/test-openssl.c | 60 +++++++++++++++++++++++++++++++++++++++
3 files changed, 125 insertions(+)
diff --git a/src/shared/openssl-util.c b/src/shared/openssl-util.c
index ecdb418402..0aef979e8c 100644
--- a/src/shared/openssl-util.c
+++ b/src/shared/openssl-util.c
@@ -118,6 +118,64 @@ int openssl_digest_size(const char *digest_alg, size_t *ret_digest_size) {
return 0;
}
+/* Calculate the digest hash value for the provided data, using the specified digest algorithm. Returns 0 on
+ * success, -EOPNOTSUPP if the digest algorithm is not supported, or < 0 for any other error. */
+int openssl_digest_many(
+ const char *digest_alg,
+ const struct iovec data[],
+ size_t n_data,
+ void **ret_digest,
+ size_t *ret_digest_size) {
+
+ int r;
+
+ assert(digest_alg);
+ assert(data || n_data == 0);
+ assert(ret_digest);
+ /* ret_digest_size is optional, as caller may already know the digest size */
+
+#if OPENSSL_VERSION_MAJOR >= 3
+ _cleanup_(EVP_MD_freep) EVP_MD *md = EVP_MD_fetch(NULL, digest_alg, NULL);
+#else
+ const EVP_MD *md = EVP_get_digestbyname(digest_alg);
+#endif
+ if (!md)
+ return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
+ "Digest algorithm '%s' not supported.", digest_alg);
+
+ _cleanup_(EVP_MD_CTX_freep) EVP_MD_CTX *ctx = EVP_MD_CTX_new();
+ if (!ctx)
+ return log_openssl_errors("Failed to create new EVP_MD_CTX");
+
+ if (!EVP_DigestInit_ex(ctx, md, NULL))
+ return log_openssl_errors("Failed to initializate EVP_MD_CTX");
+
+ for (size_t i = 0; i < n_data; i++)
+ if (!EVP_DigestUpdate(ctx, data[i].iov_base, data[i].iov_len))
+ return log_openssl_errors("Failed to update Digest");
+
+ size_t digest_size;
+ r = openssl_digest_size(digest_alg, &digest_size);
+ if (r < 0)
+ return r;
+
+ _cleanup_free_ void *buf = malloc(digest_size);
+ if (!buf)
+ return log_oom_debug();
+
+ unsigned int size;
+ if (!EVP_DigestFinal_ex(ctx, buf, &size))
+ return log_openssl_errors("Failed to finalize Digest");
+
+ assert(size == digest_size);
+
+ *ret_digest = TAKE_PTR(buf);
+ if (ret_digest_size)
+ *ret_digest_size = size;
+
+ return 0;
+}
+
int rsa_encrypt_bytes(
EVP_PKEY *pkey,
const void *decrypted_key,
diff --git a/src/shared/openssl-util.h b/src/shared/openssl-util.h
index 309dc16805..f1c84c102e 100644
--- a/src/shared/openssl-util.h
+++ b/src/shared/openssl-util.h
@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
+#include "io-util.h"
#include "macro.h"
#include "sha256.h"
@@ -60,6 +61,12 @@ int openssl_hash(const EVP_MD *alg, const void *msg, size_t msg_len, uint8_t *re
int openssl_digest_size(const char *digest_alg, size_t *ret_digest_size);
+int openssl_digest_many(const char *digest_alg, const struct iovec data[], size_t n_data, void **ret_digest, size_t *ret_digest_size);
+
+static inline int openssl_digest(const char *digest_alg, const void *buf, size_t len, void **ret_digest, size_t *ret_digest_size) {
+ return openssl_digest_many(digest_alg, &IOVEC_MAKE((void*) buf, len), 1, ret_digest, ret_digest_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);
diff --git a/src/test/test-openssl.c b/src/test/test-openssl.c
index a8a2b534a4..35ac980d25 100644
--- a/src/test/test-openssl.c
+++ b/src/test/test-openssl.c
@@ -154,4 +154,64 @@ TEST(digest_size) {
assert_se(openssl_digest_size("invalid.alg", &size) == -EOPNOTSUPP);
}
+static void verify_digest(const char *digest_alg, const struct iovec *data, size_t n_data, const char *expect) {
+ _cleanup_free_ void *digest = NULL;
+ size_t digest_size;
+ int r;
+
+ r = openssl_digest_many(digest_alg, data, n_data, &digest, &digest_size);
+ if (r == -EOPNOTSUPP)
+ return;
+ assert_se(r >= 0);
+
+ DEFINE_HEX_PTR(e, expect);
+ assert_se(memcmp_nn(e, e_len, digest, digest_size) == 0);
+}
+
+#define _DEFINE_DIGEST_TEST(uniq, alg, expect, ...) \
+ const struct iovec UNIQ_T(i, uniq)[] = { __VA_ARGS__ }; \
+ verify_digest(alg, \
+ UNIQ_T(i, uniq), \
+ ELEMENTSOF(UNIQ_T(i, uniq)), \
+ expect);
+#define DEFINE_DIGEST_TEST(alg, expect, ...) _DEFINE_DIGEST_TEST(UNIQ, alg, expect, __VA_ARGS__)
+#define DEFINE_SHA1_TEST(expect, ...) DEFINE_DIGEST_TEST("SHA1", expect, __VA_ARGS__)
+#define DEFINE_SHA256_TEST(expect, ...) DEFINE_DIGEST_TEST("SHA256", expect, __VA_ARGS__)
+#define DEFINE_SHA384_TEST(expect, ...) DEFINE_DIGEST_TEST("SHA384", expect, __VA_ARGS__)
+#define DEFINE_SHA512_TEST(expect, ...) DEFINE_DIGEST_TEST("SHA512", expect, __VA_ARGS__)
+
+TEST(digest_many) {
+ const struct iovec test = IOVEC_MAKE_STRING("test");
+
+ /* Empty digests */
+ DEFINE_SHA1_TEST("da39a3ee5e6b4b0d3255bfef95601890afd80709");
+ DEFINE_SHA256_TEST("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855");
+ DEFINE_SHA384_TEST("38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b");
+ DEFINE_SHA512_TEST("cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e");
+
+ DEFINE_SHA1_TEST("a94a8fe5ccb19ba61c4c0873d391e987982fbbd3", test);
+ DEFINE_SHA256_TEST("9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08", test);
+ DEFINE_SHA384_TEST("768412320f7b0aa5812fce428dc4706b3cae50e02a64caa16a782249bfe8efc4b7ef1ccb126255d196047dfedf17a0a9", test);
+ DEFINE_SHA512_TEST("ee26b0dd4af7e749aa1a8ee3c10ae9923f618980772e473f8819a5d4940e0db27ac185f8a0e1d5f84f88bc887fd67b143732c304cc5fa9ad8e6f57f50028a8ff", test);
+
+ DEFINE_HEX_PTR(h1, "e9ff2b6dfbc03b8dd0471a0f23840334e3ef51c64a325945524563c0375284a092751eca8d084fae22f74a104559a0ee8339d1845538481e674e6d31d4f63089");
+ DEFINE_HEX_PTR(h2, "5b6e809933a1b8d5a4a6bb62e20b36ae82d9408141e7479d0aa067273bd2d04007fb1977bad549d54330a49ed98f82b495ba");
+ DEFINE_HEX_PTR(h3, "d2aeef94d7ba2a");
+ DEFINE_HEX_PTR(h4, "1557db45ded3e38c79b5bb25c83ade42fa7d13047ef1b9a0b21a3c2ab2d4eee5c75e2927ce643163addbda65331035850a436c0acffc723f419e1d1cbf04c9064e6d850580c0732a12600f9feb");
+
+ const struct iovec i1 = IOVEC_MAKE(h1, h1_len);
+ const struct iovec i2 = IOVEC_MAKE(h2, h2_len);
+ const struct iovec i3 = IOVEC_MAKE(h3, h3_len);
+ const struct iovec i4 = IOVEC_MAKE(h4, h4_len);
+
+ DEFINE_SHA1_TEST("8e7c659a6331508b06adf98b430759dafb92fc43", i1, i2, i3, i4);
+ DEFINE_SHA256_TEST("4d6be38798786a5500651c1a02d96aa010e9d7b2bece1695294cd396d456cde8", i1, i2, i3, i4);
+ DEFINE_SHA384_TEST("82e6ec14f8d90f1ae1fd4fb7f415ea6fdb674515b13092e3e548a8d37a8faed30cda8ea613ec2a015a51bc578dacc995", i1, i2, i3, i4);
+ DEFINE_SHA512_TEST("21fe5beb15927257a9143ff59010e51d4c65c7c5237b0cd9a8db3c3fabe429be3a0759f9ace3cdd70f6ea543f998bec9bc3308833d70aa1bd380364de872a62c", i1, i2, i3, i4);
+
+ DEFINE_SHA256_TEST("0e0ed67d6717dc08dd6f472f6c35107a92b8c2695dcba344b884436f97a9eb4d", i1, i1, i1, i4);
+
+ DEFINE_SHA256_TEST("8fe8b8d1899c44bfb82e1edc4ff92642db5b2cb25c4210ea06c3846c757525a8", i1, i1, i1, i4, i4, i4, i4, i3, i3, i2);
+}
+
DEFINE_TEST_MAIN(LOG_DEBUG);