• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
free_hash_ctx(struct hash_ctx * ctx)17 static void free_hash_ctx(struct hash_ctx *ctx)
18 {
19 	free(ctx);
20 }
21 
22 /* ========== libcrypto (OpenSSL) wrappers ========== */
23 
24 struct openssl_hash_ctx {
25 	struct hash_ctx base;	/* must be first */
26 	EVP_MD_CTX *md_ctx;
27 	const EVP_MD *md;
28 };
29 
openssl_digest_init(struct hash_ctx * _ctx)30 static void openssl_digest_init(struct hash_ctx *_ctx)
31 {
32 	struct openssl_hash_ctx *ctx = (void *)_ctx;
33 
34 	if (EVP_DigestInit_ex(ctx->md_ctx, ctx->md, NULL) != 1)
35 		fatal_error("EVP_DigestInit_ex() failed for algorithm '%s'",
36 			    ctx->base.alg->name);
37 }
38 
openssl_digest_update(struct hash_ctx * _ctx,const void * data,size_t size)39 static void openssl_digest_update(struct hash_ctx *_ctx,
40 				  const void *data, size_t size)
41 {
42 	struct openssl_hash_ctx *ctx = (void *)_ctx;
43 
44 	if (EVP_DigestUpdate(ctx->md_ctx, data, size) != 1)
45 		fatal_error("EVP_DigestUpdate() failed for algorithm '%s'",
46 			    ctx->base.alg->name);
47 }
48 
openssl_digest_final(struct hash_ctx * _ctx,u8 * digest)49 static void openssl_digest_final(struct hash_ctx *_ctx, u8 *digest)
50 {
51 	struct openssl_hash_ctx *ctx = (void *)_ctx;
52 
53 	if (EVP_DigestFinal_ex(ctx->md_ctx, digest, NULL) != 1)
54 		fatal_error("EVP_DigestFinal_ex() failed for algorithm '%s'",
55 			    ctx->base.alg->name);
56 }
57 
openssl_digest_ctx_free(struct hash_ctx * _ctx)58 static void openssl_digest_ctx_free(struct hash_ctx *_ctx)
59 {
60 	struct openssl_hash_ctx *ctx = (void *)_ctx;
61 
62 	/*
63 	 * OpenSSL 1.1.0 renamed EVP_MD_CTX_destroy() to EVP_MD_CTX_free() but
64 	 * kept the old name as a macro.  Use the old name for compatibility
65 	 * with older OpenSSL versions.
66 	 */
67 	EVP_MD_CTX_destroy(ctx->md_ctx);
68 	free(ctx);
69 }
70 
71 static struct hash_ctx *
openssl_digest_ctx_create(const struct fsverity_hash_alg * alg,const EVP_MD * md)72 openssl_digest_ctx_create(const struct fsverity_hash_alg *alg, const EVP_MD *md)
73 {
74 	struct openssl_hash_ctx *ctx;
75 
76 	ctx = xzalloc(sizeof(*ctx));
77 	ctx->base.alg = alg;
78 	ctx->base.init = openssl_digest_init;
79 	ctx->base.update = openssl_digest_update;
80 	ctx->base.final = openssl_digest_final;
81 	ctx->base.free = openssl_digest_ctx_free;
82 	/*
83 	 * OpenSSL 1.1.0 renamed EVP_MD_CTX_create() to EVP_MD_CTX_new() but
84 	 * kept the old name as a macro.  Use the old name for compatibility
85 	 * with older OpenSSL versions.
86 	 */
87 	ctx->md_ctx = EVP_MD_CTX_create();
88 	if (!ctx->md_ctx)
89 		fatal_error("out of memory");
90 
91 	ctx->md = md;
92 	ASSERT(EVP_MD_size(md) == alg->digest_size);
93 
94 	return &ctx->base;
95 }
96 
create_sha256_ctx(const struct fsverity_hash_alg * alg)97 static struct hash_ctx *create_sha256_ctx(const struct fsverity_hash_alg *alg)
98 {
99 	return openssl_digest_ctx_create(alg, EVP_sha256());
100 }
101 
create_sha512_ctx(const struct fsverity_hash_alg * alg)102 static struct hash_ctx *create_sha512_ctx(const struct fsverity_hash_alg *alg)
103 {
104 	return openssl_digest_ctx_create(alg, EVP_sha512());
105 }
106 
107 /* ========== CRC-32C ========== */
108 
109 /*
110  * There are faster ways to calculate CRC's, but for now we just use the
111  * 256-entry table method as it's portable and not too complex.
112  */
113 
114 #include "crc32c_table.h"
115 
116 struct crc32c_hash_ctx {
117 	struct hash_ctx base;	/* must be first */
118 	u32 remainder;
119 };
120 
crc32c_init(struct hash_ctx * _ctx)121 static void crc32c_init(struct hash_ctx *_ctx)
122 {
123 	struct crc32c_hash_ctx *ctx = (void *)_ctx;
124 
125 	ctx->remainder = ~0;
126 }
127 
crc32c_update(struct hash_ctx * _ctx,const void * data,size_t size)128 static void crc32c_update(struct hash_ctx *_ctx, const void *data, size_t size)
129 {
130 	struct crc32c_hash_ctx *ctx = (void *)_ctx;
131 	const u8 *p = data;
132 	u32 r = ctx->remainder;
133 
134 	while (size--)
135 		r = (r >> 8) ^ crc32c_table[(u8)r ^ *p++];
136 
137 	ctx->remainder = r;
138 }
139 
crc32c_final(struct hash_ctx * _ctx,u8 * digest)140 static void crc32c_final(struct hash_ctx *_ctx, u8 *digest)
141 {
142 	struct crc32c_hash_ctx *ctx = (void *)_ctx;
143 	__le32 remainder = cpu_to_le32(~ctx->remainder);
144 
145 	memcpy(digest, &remainder, sizeof(remainder));
146 }
147 
create_crc32c_ctx(const struct fsverity_hash_alg * alg)148 static struct hash_ctx *create_crc32c_ctx(const struct fsverity_hash_alg *alg)
149 {
150 	struct crc32c_hash_ctx *ctx = xzalloc(sizeof(*ctx));
151 
152 	ctx->base.alg = alg;
153 	ctx->base.init = crc32c_init;
154 	ctx->base.update = crc32c_update;
155 	ctx->base.final = crc32c_final;
156 	ctx->base.free = free_hash_ctx;
157 	return &ctx->base;
158 }
159 
160 /* ========== Hash algorithm definitions ========== */
161 
162 const struct fsverity_hash_alg fsverity_hash_algs[] = {
163 	[FS_VERITY_ALG_SHA256] = {
164 		.name = "sha256",
165 		.digest_size = 32,
166 		.cryptographic = true,
167 		.create_ctx = create_sha256_ctx,
168 	},
169 	[FS_VERITY_ALG_SHA512] = {
170 		.name = "sha512",
171 		.digest_size = 64,
172 		.cryptographic = true,
173 		.create_ctx = create_sha512_ctx,
174 	},
175 	[FS_VERITY_ALG_CRC32C] = {
176 		.name = "crc32c",
177 		.digest_size = 4,
178 		.create_ctx = create_crc32c_ctx,
179 	},
180 };
181 
find_hash_alg_by_name(const char * name)182 const struct fsverity_hash_alg *find_hash_alg_by_name(const char *name)
183 {
184 	int i;
185 
186 	for (i = 0; i < ARRAY_SIZE(fsverity_hash_algs); i++) {
187 		if (fsverity_hash_algs[i].name &&
188 		    !strcmp(name, fsverity_hash_algs[i].name))
189 			return &fsverity_hash_algs[i];
190 	}
191 	error_msg("unknown hash algorithm: '%s'", name);
192 	fputs("Available hash algorithms: ", stderr);
193 	show_all_hash_algs(stderr);
194 	putc('\n', stderr);
195 	return NULL;
196 }
197 
find_hash_alg_by_num(unsigned int num)198 const struct fsverity_hash_alg *find_hash_alg_by_num(unsigned int num)
199 {
200 	if (num < ARRAY_SIZE(fsverity_hash_algs) &&
201 	    fsverity_hash_algs[num].name)
202 		return &fsverity_hash_algs[num];
203 
204 	return NULL;
205 }
206 
show_all_hash_algs(FILE * fp)207 void show_all_hash_algs(FILE *fp)
208 {
209 	int i;
210 	const char *sep = "";
211 
212 	for (i = 0; i < ARRAY_SIZE(fsverity_hash_algs); i++) {
213 		if (fsverity_hash_algs[i].name) {
214 			fprintf(fp, "%s%s", sep, fsverity_hash_algs[i].name);
215 			sep = ", ";
216 		}
217 	}
218 }
219