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