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 20struct openssl_hash_ctx { 21 struct hash_ctx base; /* must be first */ 22 EVP_MD_CTX *md_ctx; 23 const EVP_MD *md; 24}; 25 26static 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 35static 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 45static 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 54static 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 67static struct hash_ctx * 68openssl_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 98err2: 99 EVP_MD_CTX_destroy(ctx->md_ctx); 100err1: 101 free(ctx); 102 return NULL; 103} 104 105static struct hash_ctx *create_sha256_ctx(const struct fsverity_hash_alg *alg) 106{ 107 return openssl_digest_ctx_create(alg, EVP_sha256()); 108} 109 110static 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 117void libfsverity_hash_init(struct hash_ctx *ctx) 118{ 119 ctx->init(ctx); 120} 121 122void libfsverity_hash_update(struct hash_ctx *ctx, const void *data, 123 size_t size) 124{ 125 ctx->update(ctx, data, size); 126} 127 128void 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 */ 134void 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 142void libfsverity_free_hash_ctx(struct hash_ctx *ctx) 143{ 144 if (ctx) 145 ctx->free(ctx); 146} 147 148/* ========== Hash algorithm definitions ========== */ 149 150static 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 165LIBEXPORT u32 166libfsverity_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 181const 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 190LIBEXPORT int 191libfsverity_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 199LIBEXPORT const char * 200libfsverity_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