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