1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * fs-verity hash algorithms
4 *
5 * Copyright (C) 2018 Google LLC
6 *
7 * Written by Eric Biggers.
8 */
9
10 #include <openssl/evp.h>
11 #include <stdlib.h>
12 #include <string.h>
13
14 #include "fsverity_uapi.h"
15 #include "hash_algs.h"
16
17 /* ========== libcrypto (OpenSSL) wrappers ========== */
18
19 struct openssl_hash_ctx {
20 struct hash_ctx base; /* must be first */
21 EVP_MD_CTX *md_ctx;
22 const EVP_MD *md;
23 };
24
openssl_digest_init(struct hash_ctx * _ctx)25 static void openssl_digest_init(struct hash_ctx *_ctx)
26 {
27 struct openssl_hash_ctx *ctx = (void *)_ctx;
28
29 if (EVP_DigestInit_ex(ctx->md_ctx, ctx->md, NULL) != 1)
30 fatal_error("EVP_DigestInit_ex() failed for algorithm '%s'",
31 ctx->base.alg->name);
32 }
33
openssl_digest_update(struct hash_ctx * _ctx,const void * data,size_t size)34 static void openssl_digest_update(struct hash_ctx *_ctx,
35 const void *data, size_t size)
36 {
37 struct openssl_hash_ctx *ctx = (void *)_ctx;
38
39 if (EVP_DigestUpdate(ctx->md_ctx, data, size) != 1)
40 fatal_error("EVP_DigestUpdate() failed for algorithm '%s'",
41 ctx->base.alg->name);
42 }
43
openssl_digest_final(struct hash_ctx * _ctx,u8 * digest)44 static void openssl_digest_final(struct hash_ctx *_ctx, u8 *digest)
45 {
46 struct openssl_hash_ctx *ctx = (void *)_ctx;
47
48 if (EVP_DigestFinal_ex(ctx->md_ctx, digest, NULL) != 1)
49 fatal_error("EVP_DigestFinal_ex() failed for algorithm '%s'",
50 ctx->base.alg->name);
51 }
52
openssl_digest_ctx_free(struct hash_ctx * _ctx)53 static void openssl_digest_ctx_free(struct hash_ctx *_ctx)
54 {
55 struct openssl_hash_ctx *ctx = (void *)_ctx;
56
57 /*
58 * OpenSSL 1.1.0 renamed EVP_MD_CTX_destroy() to EVP_MD_CTX_free() but
59 * kept the old name as a macro. Use the old name for compatibility
60 * with older OpenSSL versions.
61 */
62 EVP_MD_CTX_destroy(ctx->md_ctx);
63 free(ctx);
64 }
65
66 static struct hash_ctx *
openssl_digest_ctx_create(const struct fsverity_hash_alg * alg,const EVP_MD * md)67 openssl_digest_ctx_create(const struct fsverity_hash_alg *alg, const EVP_MD *md)
68 {
69 struct openssl_hash_ctx *ctx;
70
71 ctx = xzalloc(sizeof(*ctx));
72 ctx->base.alg = alg;
73 ctx->base.init = openssl_digest_init;
74 ctx->base.update = openssl_digest_update;
75 ctx->base.final = openssl_digest_final;
76 ctx->base.free = openssl_digest_ctx_free;
77 /*
78 * OpenSSL 1.1.0 renamed EVP_MD_CTX_create() to EVP_MD_CTX_new() but
79 * kept the old name as a macro. Use the old name for compatibility
80 * with older OpenSSL versions.
81 */
82 ctx->md_ctx = EVP_MD_CTX_create();
83 if (!ctx->md_ctx)
84 fatal_error("out of memory");
85
86 ctx->md = md;
87 ASSERT(EVP_MD_size(md) == alg->digest_size);
88
89 return &ctx->base;
90 }
91
create_sha256_ctx(const struct fsverity_hash_alg * alg)92 static struct hash_ctx *create_sha256_ctx(const struct fsverity_hash_alg *alg)
93 {
94 return openssl_digest_ctx_create(alg, EVP_sha256());
95 }
96
create_sha512_ctx(const struct fsverity_hash_alg * alg)97 static struct hash_ctx *create_sha512_ctx(const struct fsverity_hash_alg *alg)
98 {
99 return openssl_digest_ctx_create(alg, EVP_sha512());
100 }
101
102 /* ========== Hash algorithm definitions ========== */
103
104 const struct fsverity_hash_alg fsverity_hash_algs[] = {
105 [FS_VERITY_HASH_ALG_SHA256] = {
106 .name = "sha256",
107 .digest_size = 32,
108 .block_size = 64,
109 .create_ctx = create_sha256_ctx,
110 },
111 [FS_VERITY_HASH_ALG_SHA512] = {
112 .name = "sha512",
113 .digest_size = 64,
114 .block_size = 128,
115 .create_ctx = create_sha512_ctx,
116 },
117 };
118
find_hash_alg_by_name(const char * name)119 const struct fsverity_hash_alg *find_hash_alg_by_name(const char *name)
120 {
121 int i;
122
123 for (i = 0; i < ARRAY_SIZE(fsverity_hash_algs); i++) {
124 if (fsverity_hash_algs[i].name &&
125 !strcmp(name, fsverity_hash_algs[i].name))
126 return &fsverity_hash_algs[i];
127 }
128 error_msg("unknown hash algorithm: '%s'", name);
129 fputs("Available hash algorithms: ", stderr);
130 show_all_hash_algs(stderr);
131 putc('\n', stderr);
132 return NULL;
133 }
134
find_hash_alg_by_num(unsigned int num)135 const struct fsverity_hash_alg *find_hash_alg_by_num(unsigned int num)
136 {
137 if (num < ARRAY_SIZE(fsverity_hash_algs) &&
138 fsverity_hash_algs[num].name)
139 return &fsverity_hash_algs[num];
140
141 return NULL;
142 }
143
show_all_hash_algs(FILE * fp)144 void show_all_hash_algs(FILE *fp)
145 {
146 int i;
147 const char *sep = "";
148
149 for (i = 0; i < ARRAY_SIZE(fsverity_hash_algs); i++) {
150 if (fsverity_hash_algs[i].name) {
151 fprintf(fp, "%s%s", sep, fsverity_hash_algs[i].name);
152 sep = ", ";
153 }
154 }
155 }
156
157 /* ->init(), ->update(), and ->final() all in one step */
hash_full(struct hash_ctx * ctx,const void * data,size_t size,u8 * digest)158 void hash_full(struct hash_ctx *ctx, const void *data, size_t size, u8 *digest)
159 {
160 hash_init(ctx);
161 hash_update(ctx, data, size);
162 hash_final(ctx, digest);
163 }
164