1ced56a00Sopenharmony_ci// SPDX-License-Identifier: MIT
2ced56a00Sopenharmony_ci/*
3ced56a00Sopenharmony_ci * fs-verity hash algorithms
4ced56a00Sopenharmony_ci *
5ced56a00Sopenharmony_ci * Copyright 2018 Google LLC
6ced56a00Sopenharmony_ci *
7ced56a00Sopenharmony_ci * Use of this source code is governed by an MIT-style
8ced56a00Sopenharmony_ci * license that can be found in the LICENSE file or at
9ced56a00Sopenharmony_ci * https://opensource.org/licenses/MIT.
10ced56a00Sopenharmony_ci */
11ced56a00Sopenharmony_ci
12ced56a00Sopenharmony_ci#include "lib_private.h"
13ced56a00Sopenharmony_ci
14ced56a00Sopenharmony_ci#include <openssl/evp.h>
15ced56a00Sopenharmony_ci#include <stdlib.h>
16ced56a00Sopenharmony_ci#include <string.h>
17ced56a00Sopenharmony_ci
18ced56a00Sopenharmony_ci/* ========== libcrypto (OpenSSL) wrappers ========== */
19ced56a00Sopenharmony_ci
20ced56a00Sopenharmony_cistruct openssl_hash_ctx {
21ced56a00Sopenharmony_ci	struct hash_ctx base;	/* must be first */
22ced56a00Sopenharmony_ci	EVP_MD_CTX *md_ctx;
23ced56a00Sopenharmony_ci	const EVP_MD *md;
24ced56a00Sopenharmony_ci};
25ced56a00Sopenharmony_ci
26ced56a00Sopenharmony_cistatic void openssl_digest_init(struct hash_ctx *_ctx)
27ced56a00Sopenharmony_ci{
28ced56a00Sopenharmony_ci	struct openssl_hash_ctx *ctx = (void *)_ctx;
29ced56a00Sopenharmony_ci	int ret;
30ced56a00Sopenharmony_ci
31ced56a00Sopenharmony_ci	ret = EVP_DigestInit_ex(ctx->md_ctx, ctx->md, NULL);
32ced56a00Sopenharmony_ci	BUG_ON(ret != 1);
33ced56a00Sopenharmony_ci}
34ced56a00Sopenharmony_ci
35ced56a00Sopenharmony_cistatic void openssl_digest_update(struct hash_ctx *_ctx,
36ced56a00Sopenharmony_ci				  const void *data, size_t size)
37ced56a00Sopenharmony_ci{
38ced56a00Sopenharmony_ci	struct openssl_hash_ctx *ctx = (void *)_ctx;
39ced56a00Sopenharmony_ci	int ret;
40ced56a00Sopenharmony_ci
41ced56a00Sopenharmony_ci	ret = EVP_DigestUpdate(ctx->md_ctx, data, size);
42ced56a00Sopenharmony_ci	BUG_ON(ret != 1);
43ced56a00Sopenharmony_ci}
44ced56a00Sopenharmony_ci
45ced56a00Sopenharmony_cistatic void openssl_digest_final(struct hash_ctx *_ctx, u8 *digest)
46ced56a00Sopenharmony_ci{
47ced56a00Sopenharmony_ci	struct openssl_hash_ctx *ctx = (void *)_ctx;
48ced56a00Sopenharmony_ci	int ret;
49ced56a00Sopenharmony_ci
50ced56a00Sopenharmony_ci	ret = EVP_DigestFinal_ex(ctx->md_ctx, digest, NULL);
51ced56a00Sopenharmony_ci	BUG_ON(ret != 1);
52ced56a00Sopenharmony_ci}
53ced56a00Sopenharmony_ci
54ced56a00Sopenharmony_cistatic void openssl_digest_ctx_free(struct hash_ctx *_ctx)
55ced56a00Sopenharmony_ci{
56ced56a00Sopenharmony_ci	struct openssl_hash_ctx *ctx = (void *)_ctx;
57ced56a00Sopenharmony_ci
58ced56a00Sopenharmony_ci	/*
59ced56a00Sopenharmony_ci	 * OpenSSL 1.1.0 renamed EVP_MD_CTX_destroy() to EVP_MD_CTX_free() but
60ced56a00Sopenharmony_ci	 * kept the old name as a macro.  Use the old name for compatibility
61ced56a00Sopenharmony_ci	 * with older OpenSSL versions.
62ced56a00Sopenharmony_ci	 */
63ced56a00Sopenharmony_ci	EVP_MD_CTX_destroy(ctx->md_ctx);
64ced56a00Sopenharmony_ci	free(ctx);
65ced56a00Sopenharmony_ci}
66ced56a00Sopenharmony_ci
67ced56a00Sopenharmony_cistatic struct hash_ctx *
68ced56a00Sopenharmony_ciopenssl_digest_ctx_create(const struct fsverity_hash_alg *alg, const EVP_MD *md)
69ced56a00Sopenharmony_ci{
70ced56a00Sopenharmony_ci	struct openssl_hash_ctx *ctx;
71ced56a00Sopenharmony_ci
72ced56a00Sopenharmony_ci	ctx = libfsverity_zalloc(sizeof(*ctx));
73ced56a00Sopenharmony_ci	if (!ctx)
74ced56a00Sopenharmony_ci		return NULL;
75ced56a00Sopenharmony_ci
76ced56a00Sopenharmony_ci	ctx->base.alg = alg;
77ced56a00Sopenharmony_ci	ctx->base.init = openssl_digest_init;
78ced56a00Sopenharmony_ci	ctx->base.update = openssl_digest_update;
79ced56a00Sopenharmony_ci	ctx->base.final = openssl_digest_final;
80ced56a00Sopenharmony_ci	ctx->base.free = openssl_digest_ctx_free;
81ced56a00Sopenharmony_ci	/*
82ced56a00Sopenharmony_ci	 * OpenSSL 1.1.0 renamed EVP_MD_CTX_create() to EVP_MD_CTX_new() but
83ced56a00Sopenharmony_ci	 * kept the old name as a macro.  Use the old name for compatibility
84ced56a00Sopenharmony_ci	 * with older OpenSSL versions.
85ced56a00Sopenharmony_ci	 */
86ced56a00Sopenharmony_ci	ctx->md_ctx = EVP_MD_CTX_create();
87ced56a00Sopenharmony_ci	if (!ctx->md_ctx) {
88ced56a00Sopenharmony_ci		libfsverity_error_msg("failed to allocate EVP_MD_CTX");
89ced56a00Sopenharmony_ci		goto err1;
90ced56a00Sopenharmony_ci	}
91ced56a00Sopenharmony_ci
92ced56a00Sopenharmony_ci	ctx->md = md;
93ced56a00Sopenharmony_ci	if (WARN_ON(EVP_MD_size(md) != alg->digest_size))
94ced56a00Sopenharmony_ci		goto err2;
95ced56a00Sopenharmony_ci
96ced56a00Sopenharmony_ci	return &ctx->base;
97ced56a00Sopenharmony_ci
98ced56a00Sopenharmony_cierr2:
99ced56a00Sopenharmony_ci	EVP_MD_CTX_destroy(ctx->md_ctx);
100ced56a00Sopenharmony_cierr1:
101ced56a00Sopenharmony_ci	free(ctx);
102ced56a00Sopenharmony_ci	return NULL;
103ced56a00Sopenharmony_ci}
104ced56a00Sopenharmony_ci
105ced56a00Sopenharmony_cistatic struct hash_ctx *create_sha256_ctx(const struct fsverity_hash_alg *alg)
106ced56a00Sopenharmony_ci{
107ced56a00Sopenharmony_ci	return openssl_digest_ctx_create(alg, EVP_sha256());
108ced56a00Sopenharmony_ci}
109ced56a00Sopenharmony_ci
110ced56a00Sopenharmony_cistatic struct hash_ctx *create_sha512_ctx(const struct fsverity_hash_alg *alg)
111ced56a00Sopenharmony_ci{
112ced56a00Sopenharmony_ci	return openssl_digest_ctx_create(alg, EVP_sha512());
113ced56a00Sopenharmony_ci}
114ced56a00Sopenharmony_ci
115ced56a00Sopenharmony_ci/* ========== Hash utilities ========== */
116ced56a00Sopenharmony_ci
117ced56a00Sopenharmony_civoid libfsverity_hash_init(struct hash_ctx *ctx)
118ced56a00Sopenharmony_ci{
119ced56a00Sopenharmony_ci	ctx->init(ctx);
120ced56a00Sopenharmony_ci}
121ced56a00Sopenharmony_ci
122ced56a00Sopenharmony_civoid libfsverity_hash_update(struct hash_ctx *ctx, const void *data,
123ced56a00Sopenharmony_ci			     size_t size)
124ced56a00Sopenharmony_ci{
125ced56a00Sopenharmony_ci	ctx->update(ctx, data, size);
126ced56a00Sopenharmony_ci}
127ced56a00Sopenharmony_ci
128ced56a00Sopenharmony_civoid libfsverity_hash_final(struct hash_ctx *ctx, u8 *digest)
129ced56a00Sopenharmony_ci{
130ced56a00Sopenharmony_ci	ctx->final(ctx, digest);
131ced56a00Sopenharmony_ci}
132ced56a00Sopenharmony_ci
133ced56a00Sopenharmony_ci/* ->init(), ->update(), and ->final() all in one step */
134ced56a00Sopenharmony_civoid libfsverity_hash_full(struct hash_ctx *ctx, const void *data, size_t size,
135ced56a00Sopenharmony_ci			   u8 *digest)
136ced56a00Sopenharmony_ci{
137ced56a00Sopenharmony_ci	libfsverity_hash_init(ctx);
138ced56a00Sopenharmony_ci	libfsverity_hash_update(ctx, data, size);
139ced56a00Sopenharmony_ci	libfsverity_hash_final(ctx, digest);
140ced56a00Sopenharmony_ci}
141ced56a00Sopenharmony_ci
142ced56a00Sopenharmony_civoid libfsverity_free_hash_ctx(struct hash_ctx *ctx)
143ced56a00Sopenharmony_ci{
144ced56a00Sopenharmony_ci	if (ctx)
145ced56a00Sopenharmony_ci		ctx->free(ctx);
146ced56a00Sopenharmony_ci}
147ced56a00Sopenharmony_ci
148ced56a00Sopenharmony_ci/* ========== Hash algorithm definitions ========== */
149ced56a00Sopenharmony_ci
150ced56a00Sopenharmony_cistatic const struct fsverity_hash_alg fsverity_hash_algs[] = {
151ced56a00Sopenharmony_ci	[FS_VERITY_HASH_ALG_SHA256] = {
152ced56a00Sopenharmony_ci		.name = "sha256",
153ced56a00Sopenharmony_ci		.digest_size = 32,
154ced56a00Sopenharmony_ci		.block_size = 64,
155ced56a00Sopenharmony_ci		.create_ctx = create_sha256_ctx,
156ced56a00Sopenharmony_ci	},
157ced56a00Sopenharmony_ci	[FS_VERITY_HASH_ALG_SHA512] = {
158ced56a00Sopenharmony_ci		.name = "sha512",
159ced56a00Sopenharmony_ci		.digest_size = 64,
160ced56a00Sopenharmony_ci		.block_size = 128,
161ced56a00Sopenharmony_ci		.create_ctx = create_sha512_ctx,
162ced56a00Sopenharmony_ci	},
163ced56a00Sopenharmony_ci};
164ced56a00Sopenharmony_ci
165ced56a00Sopenharmony_ciLIBEXPORT u32
166ced56a00Sopenharmony_cilibfsverity_find_hash_alg_by_name(const char *name)
167ced56a00Sopenharmony_ci{
168ced56a00Sopenharmony_ci	int i;
169ced56a00Sopenharmony_ci
170ced56a00Sopenharmony_ci	if (!name)
171ced56a00Sopenharmony_ci		return 0;
172ced56a00Sopenharmony_ci
173ced56a00Sopenharmony_ci	for (i = 1; i < ARRAY_SIZE(fsverity_hash_algs); i++) {
174ced56a00Sopenharmony_ci		if (fsverity_hash_algs[i].name &&
175ced56a00Sopenharmony_ci		    !strcmp(name, fsverity_hash_algs[i].name))
176ced56a00Sopenharmony_ci			return i;
177ced56a00Sopenharmony_ci	}
178ced56a00Sopenharmony_ci	return 0;
179ced56a00Sopenharmony_ci}
180ced56a00Sopenharmony_ci
181ced56a00Sopenharmony_ciconst struct fsverity_hash_alg *libfsverity_find_hash_alg_by_num(u32 alg_num)
182ced56a00Sopenharmony_ci{
183ced56a00Sopenharmony_ci	if (alg_num < ARRAY_SIZE(fsverity_hash_algs) &&
184ced56a00Sopenharmony_ci	    fsverity_hash_algs[alg_num].name)
185ced56a00Sopenharmony_ci		return &fsverity_hash_algs[alg_num];
186ced56a00Sopenharmony_ci
187ced56a00Sopenharmony_ci	return NULL;
188ced56a00Sopenharmony_ci}
189ced56a00Sopenharmony_ci
190ced56a00Sopenharmony_ciLIBEXPORT int
191ced56a00Sopenharmony_cilibfsverity_get_digest_size(u32 alg_num)
192ced56a00Sopenharmony_ci{
193ced56a00Sopenharmony_ci	const struct fsverity_hash_alg *alg =
194ced56a00Sopenharmony_ci		libfsverity_find_hash_alg_by_num(alg_num);
195ced56a00Sopenharmony_ci
196ced56a00Sopenharmony_ci	return alg ? alg->digest_size : -1;
197ced56a00Sopenharmony_ci}
198ced56a00Sopenharmony_ci
199ced56a00Sopenharmony_ciLIBEXPORT const char *
200ced56a00Sopenharmony_cilibfsverity_get_hash_name(u32 alg_num)
201ced56a00Sopenharmony_ci{
202ced56a00Sopenharmony_ci	const struct fsverity_hash_alg *alg =
203ced56a00Sopenharmony_ci		libfsverity_find_hash_alg_by_num(alg_num);
204ced56a00Sopenharmony_ci
205ced56a00Sopenharmony_ci	return alg ? alg->name : NULL;
206ced56a00Sopenharmony_ci}
207