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