• 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 
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