| // Copyright 2022 The ChromiumOS Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "libhwsec/backend/digest_algorithms.h" |
| |
| #include <algorithm> |
| #include <optional> |
| #include <string> |
| |
| #include <brillo/secure_blob.h> |
| #include <crypto/scoped_openssl_types.h> |
| #include <openssl/evp.h> |
| |
| #include "libhwsec/status.h" |
| |
| using hwsec_foundation::status::MakeStatus; |
| |
| namespace hwsec { |
| |
| namespace { |
| |
| // The DER encoding of MD5 DigestInfo as defined in PKCS #1. |
| constexpr uint8_t kMd5DigestInfo[] = {0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, |
| 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, |
| 0x02, 0x05, 0x05, 0x00, 0x04, 0x10}; |
| |
| // The DER encoding of SHA-1 DigestInfo as defined in PKCS #1. |
| constexpr uint8_t kSha1DigestInfo[] = {0x30, 0x21, 0x30, 0x09, 0x06, |
| 0x05, 0x2b, 0x0e, 0x03, 0x02, |
| 0x1a, 0x05, 0x00, 0x04, 0x14}; |
| |
| // The DER encoding of SHA-256 DigestInfo as defined in PKCS #1. |
| constexpr uint8_t kSha256DigestInfo[] = { |
| 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, |
| 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20}; |
| |
| // The DER encoding of SHA-384 DigestInfo as defined in PKCS #1. |
| constexpr uint8_t kSha384DigestInfo[] = { |
| 0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, |
| 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00, 0x04, 0x30}; |
| |
| // The DER encoding of SHA-512 DigestInfo as defined in PKCS #1. |
| constexpr uint8_t kSha512DigestInfo[] = { |
| 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, |
| 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40}; |
| |
| // Empty digset info. |
| constexpr uint8_t kNoDigestInfo[] = {}; |
| |
| constexpr struct { |
| DigestAlgorithm algorithm; |
| const uint8_t* digest_info; |
| size_t len; |
| } kDigestInfos[] = { |
| { |
| .algorithm = DigestAlgorithm::kNoDigest, |
| .digest_info = kNoDigestInfo, |
| .len = sizeof(kNoDigestInfo), |
| }, |
| { |
| .algorithm = DigestAlgorithm::kMd5, |
| .digest_info = kMd5DigestInfo, |
| .len = sizeof(kMd5DigestInfo), |
| }, |
| { |
| .algorithm = DigestAlgorithm::kSha1, |
| .digest_info = kSha1DigestInfo, |
| .len = sizeof(kSha1DigestInfo), |
| }, |
| { |
| .algorithm = DigestAlgorithm::kSha256, |
| .digest_info = kSha256DigestInfo, |
| .len = sizeof(kSha256DigestInfo), |
| }, |
| { |
| .algorithm = DigestAlgorithm::kSha384, |
| .digest_info = kSha384DigestInfo, |
| .len = sizeof(kSha384DigestInfo), |
| }, |
| { |
| .algorithm = DigestAlgorithm::kSha512, |
| .digest_info = kSha512DigestInfo, |
| .len = sizeof(kSha512DigestInfo), |
| }, |
| }; |
| |
| } // namespace |
| |
| std::optional<ParsedDigestInfo> ParseDigestInfo(const brillo::Blob& input) { |
| for (const auto& info : kDigestInfos) { |
| if (input.size() == GetDigestLength(info.algorithm) + info.len) { |
| if (std::equal(info.digest_info, info.digest_info + info.len, |
| input.begin())) { |
| return ParsedDigestInfo{ |
| .algorithm = info.algorithm, |
| .blob = brillo::Blob(input.begin() + info.len, input.end()), |
| }; |
| } |
| } |
| } |
| return std::nullopt; |
| } |
| |
| StatusOr<brillo::Blob> GetDigestAlgorithmEncoding(DigestAlgorithm algo) { |
| for (const auto& info : kDigestInfos) { |
| if (info.algorithm == algo) { |
| return brillo::Blob(info.digest_info, info.digest_info + info.len); |
| } |
| } |
| return MakeStatus<TPMError>("Unsupported digest info", |
| TPMRetryAction::kNoRetry); |
| } |
| |
| StatusOr<brillo::Blob> DigestData(DigestAlgorithm algo, brillo::Blob data) { |
| const EVP_MD* digest_type = GetOpenSSLDigest(algo); |
| if (digest_type == nullptr) { |
| return data; |
| } |
| |
| brillo::Blob result(EVP_MD_size(digest_type)); |
| unsigned int result_size = 0; |
| |
| crypto::ScopedEVP_MD_CTX ctx(EVP_MD_CTX_new()); |
| |
| if (!EVP_DigestInit(ctx.get(), digest_type)) { |
| return MakeStatus<TPMError>("EVP_DigestInit failed", |
| TPMRetryAction::kNoRetry); |
| } |
| |
| if (!EVP_DigestUpdate(ctx.get(), data.data(), data.size())) { |
| return MakeStatus<TPMError>("EVP_DigestUpdate failed", |
| TPMRetryAction::kNoRetry); |
| } |
| |
| if (!EVP_DigestFinal(ctx.get(), result.data(), &result_size)) { |
| return MakeStatus<TPMError>("EVP_DigestUpdate failed", |
| TPMRetryAction::kNoRetry); |
| } |
| |
| if (result_size != result.size()) { |
| return MakeStatus<TPMError>("Digest result size mismatch", |
| TPMRetryAction::kNoRetry); |
| } |
| |
| return result; |
| } |
| |
| } // namespace hwsec |