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