| // SPDX-License-Identifier: GPL-2.0 |
| /* |
| * Copyright (C) 2020-2024 Microsoft Corporation. All rights reserved. |
| */ |
| |
| #include "digest.h" |
| |
| /** |
| * ipe_digest_parse() - parse a digest in IPE's policy. |
| * @valstr: Supplies the string parsed from the policy. |
| * |
| * Digests in IPE are defined in a standard way: |
| * <alg_name>:<hex> |
| * |
| * Use this function to create a property to parse the digest |
| * consistently. The parsed digest will be saved in @value in IPE's |
| * policy. |
| * |
| * Return: The parsed digest_info structure on success. If an error occurs, |
| * the function will return the error value (via ERR_PTR). |
| */ |
| struct digest_info *ipe_digest_parse(const char *valstr) |
| { |
| struct digest_info *info = NULL; |
| char *sep, *raw_digest; |
| size_t raw_digest_len; |
| u8 *digest = NULL; |
| char *alg = NULL; |
| int rc = 0; |
| |
| info = kzalloc(sizeof(*info), GFP_KERNEL); |
| if (!info) |
| return ERR_PTR(-ENOMEM); |
| |
| sep = strchr(valstr, ':'); |
| if (!sep) { |
| rc = -EBADMSG; |
| goto err; |
| } |
| |
| alg = kstrndup(valstr, sep - valstr, GFP_KERNEL); |
| if (!alg) { |
| rc = -ENOMEM; |
| goto err; |
| } |
| |
| raw_digest = sep + 1; |
| raw_digest_len = strlen(raw_digest); |
| |
| info->digest_len = (raw_digest_len + 1) / 2; |
| digest = kzalloc(info->digest_len, GFP_KERNEL); |
| if (!digest) { |
| rc = -ENOMEM; |
| goto err; |
| } |
| |
| rc = hex2bin(digest, raw_digest, info->digest_len); |
| if (rc < 0) { |
| rc = -EINVAL; |
| goto err; |
| } |
| |
| info->alg = alg; |
| info->digest = digest; |
| return info; |
| |
| err: |
| kfree(alg); |
| kfree(digest); |
| kfree(info); |
| return ERR_PTR(rc); |
| } |
| |
| /** |
| * ipe_digest_eval() - evaluate an IPE digest against another digest. |
| * @expected: Supplies the policy-provided digest value. |
| * @digest: Supplies the digest to compare against the policy digest value. |
| * |
| * Return: |
| * * %true - digests match |
| * * %false - digests do not match |
| */ |
| bool ipe_digest_eval(const struct digest_info *expected, |
| const struct digest_info *digest) |
| { |
| return (expected->digest_len == digest->digest_len) && |
| (!strcmp(expected->alg, digest->alg)) && |
| (!memcmp(expected->digest, digest->digest, expected->digest_len)); |
| } |
| |
| /** |
| * ipe_digest_free() - free an IPE digest. |
| * @info: Supplies a pointer the policy-provided digest to free. |
| */ |
| void ipe_digest_free(struct digest_info *info) |
| { |
| if (IS_ERR_OR_NULL(info)) |
| return; |
| |
| kfree(info->alg); |
| kfree(info->digest); |
| kfree(info); |
| } |
| |
| /** |
| * ipe_digest_audit() - audit a digest that was sourced from IPE's policy. |
| * @ab: Supplies the audit_buffer to append the formatted result. |
| * @info: Supplies a pointer to source the audit record from. |
| * |
| * Digests in IPE are audited in this format: |
| * <alg_name>:<hex> |
| */ |
| void ipe_digest_audit(struct audit_buffer *ab, const struct digest_info *info) |
| { |
| audit_log_untrustedstring(ab, info->alg); |
| audit_log_format(ab, ":"); |
| audit_log_n_hex(ab, info->digest, info->digest_len); |
| } |