Home | History | Annotate | Download | only in fsverity-utils
      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 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 
     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 
     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 
     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 
     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 *
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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