blob: 031032abdb24c7650d211767707139859af7ad0f [file] [log] [blame]
// 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 <optional>
#include <utility>
#include <variant>
#include <brillo/secure_blob.h>
#include <gtest/gtest.h>
#include "cryptohome/flatbuffer_schemas/auth_block_state.h"
#include "cryptohome/flatbuffer_schemas/auth_block_state_test_utils.h"
using brillo::Blob;
using brillo::BlobFromString;
using brillo::SecureBlob;
namespace cryptohome {
namespace {
constexpr int kWorkFactor = 16384;
constexpr int kBlockSize = 8;
constexpr int kParallelFactor = 1;
const SecureBlob kSalt = SecureBlob("salt");
const SecureBlob kChapsSalt = SecureBlob("chaps_salt");
const SecureBlob kResetSeedSalt = SecureBlob("reset_seed_salt");
} // namespace
TEST(AuthBlockStateBindingTest, EmptyState) {
AuthBlockState state;
std::optional<SecureBlob> blob = state.Serialize();
ASSERT_TRUE(blob.has_value());
std::optional<AuthBlockState> state2 =
AuthBlockState::Deserialize(blob.value());
ASSERT_TRUE(state2.has_value());
EXPECT_EQ(state, state2);
}
TEST(AuthBlockStateBindingTest, ScryptAuthBlockState) {
AuthBlockState state = {.state = ScryptAuthBlockState{
.salt = kSalt,
.chaps_salt = kChapsSalt,
.reset_seed_salt = kResetSeedSalt,
.work_factor = kWorkFactor,
.block_size = kBlockSize,
.parallel_factor = kParallelFactor,
}};
std::optional<SecureBlob> blob = state.Serialize();
ASSERT_TRUE(blob.has_value());
std::optional<AuthBlockState> state2 =
AuthBlockState::Deserialize(blob.value());
ASSERT_TRUE(state2.has_value());
EXPECT_EQ(state, state2);
}
TEST(AuthBlockStateBindingTest, ScryptAuthBlockStateEmpty) {
AuthBlockState state = {.state = ScryptAuthBlockState{}};
std::optional<SecureBlob> blob = state.Serialize();
ASSERT_TRUE(blob.has_value());
std::optional<AuthBlockState> state2 =
AuthBlockState::Deserialize(blob.value());
ASSERT_TRUE(state2.has_value());
EXPECT_EQ(state, state2);
}
TEST(AuthBlockStateBindingTest, LibScryptCompatAuthBlockStateNotEqual) {
AuthBlockState state = {.state = ScryptAuthBlockState{}};
std::optional<SecureBlob> blob = state.Serialize();
ASSERT_TRUE(blob.has_value());
std::optional<AuthBlockState> state2 =
AuthBlockState::Deserialize(blob.value());
ASSERT_TRUE(state2.has_value());
state.state = ScryptAuthBlockState{
.salt = SecureBlob(""),
.chaps_salt = SecureBlob(""),
.reset_seed_salt = SecureBlob(""),
.work_factor = kWorkFactor,
.block_size = kBlockSize,
.parallel_factor = kParallelFactor,
};
EXPECT_NE(state, state2);
}
TEST(AuthBlockStateBindingTest, TpmNotBoundToPcrAuthBlockState) {
AuthBlockState state = {
.state = TpmNotBoundToPcrAuthBlockState{
.scrypt_derived = true,
.salt = kSalt,
.password_rounds = 1234,
.tpm_key = SecureBlob("tpm_key"),
.tpm_public_key_hash = SecureBlob("tpm_public_key_hash"),
}};
std::optional<SecureBlob> blob = state.Serialize();
ASSERT_TRUE(blob.has_value());
std::optional<AuthBlockState> state2 =
AuthBlockState::Deserialize(blob.value());
ASSERT_TRUE(state2.has_value());
EXPECT_EQ(state, state2);
}
TEST(AuthBlockStateBindingTest, TpmNotBoundToPcrAuthBlockStateOptional) {
AuthBlockState state1 = {.state = TpmNotBoundToPcrAuthBlockState{}};
std::optional<SecureBlob> blob1 = state1.Serialize();
ASSERT_TRUE(blob1.has_value());
std::optional<AuthBlockState> state1_new =
AuthBlockState::Deserialize(blob1.value());
ASSERT_TRUE(state1_new.has_value());
EXPECT_EQ(state1, state1_new);
AuthBlockState state2 = {.state = TpmNotBoundToPcrAuthBlockState{
.password_rounds = 0,
}};
std::optional<SecureBlob> blob2 = state2.Serialize();
ASSERT_TRUE(blob2.has_value());
std::optional<AuthBlockState> state2_new =
AuthBlockState::Deserialize(blob2.value());
ASSERT_TRUE(state2_new.has_value());
EXPECT_EQ(state2, state2_new);
AuthBlockState state3 = {.state = TpmNotBoundToPcrAuthBlockState{
.scrypt_derived = false,
}};
std::optional<SecureBlob> blob3 = state3.Serialize();
ASSERT_TRUE(blob3.has_value());
std::optional<AuthBlockState> state3_new =
AuthBlockState::Deserialize(blob3.value());
ASSERT_TRUE(state3_new.has_value());
EXPECT_EQ(state3, state3_new);
AuthBlockState state4 = {.state = TpmNotBoundToPcrAuthBlockState{
.scrypt_derived = false,
.password_rounds = 0,
}};
std::optional<SecureBlob> blob4 = state4.Serialize();
ASSERT_TRUE(blob4.has_value());
std::optional<AuthBlockState> state4_new =
AuthBlockState::Deserialize(blob4.value());
ASSERT_TRUE(state4_new.has_value());
EXPECT_EQ(state4, state4_new);
EXPECT_NE(state1, state2);
EXPECT_NE(state1, state2_new);
EXPECT_NE(state1_new, state2);
EXPECT_NE(state1_new, state2_new);
EXPECT_NE(state3, state4);
EXPECT_NE(state3, state4_new);
EXPECT_NE(state3_new, state4);
EXPECT_NE(state3_new, state4_new);
EXPECT_NE(state1, state3);
EXPECT_NE(state2, state4);
EXPECT_NE(state1, state3_new);
EXPECT_NE(state2, state4_new);
EXPECT_NE(state1_new, state3);
EXPECT_NE(state2_new, state4);
EXPECT_NE(state1_new, state3_new);
EXPECT_NE(state2_new, state4_new);
}
TEST(AuthBlockStateBindingTest, TpmNotBoundToPcrAuthBlockStateEmpty) {
AuthBlockState state = {.state = TpmNotBoundToPcrAuthBlockState{
.salt = SecureBlob(""),
.tpm_key = SecureBlob(""),
.tpm_public_key_hash = SecureBlob(""),
}};
std::optional<SecureBlob> blob = state.Serialize();
ASSERT_TRUE(blob.has_value());
std::optional<AuthBlockState> state2 =
AuthBlockState::Deserialize(blob.value());
ASSERT_TRUE(state2.has_value());
EXPECT_EQ(state, state2);
}
TEST(AuthBlockStateBindingTest, DoubleWrappedCompatAuthBlockState) {
AuthBlockState state = {
.state = DoubleWrappedCompatAuthBlockState{
.scrypt_state =
ScryptAuthBlockState{
.salt = kSalt,
.chaps_salt = kChapsSalt,
.reset_seed_salt = kResetSeedSalt,
.work_factor = kWorkFactor,
.block_size = kBlockSize,
.parallel_factor = kParallelFactor,
},
.tpm_state = TpmNotBoundToPcrAuthBlockState{
.scrypt_derived = true,
.salt = kSalt,
.password_rounds = 1234,
.tpm_key = SecureBlob("tpm_key"),
.tpm_public_key_hash = SecureBlob("tpm_public_key_hash"),
}}};
std::optional<SecureBlob> blob = state.Serialize();
ASSERT_TRUE(blob.has_value());
std::optional<AuthBlockState> state2 =
AuthBlockState::Deserialize(blob.value());
ASSERT_TRUE(state2.has_value());
EXPECT_EQ(state, state2);
}
TEST(AuthBlockStateBindingTest, ChallengeCredentialAuthBlockStateTpm12) {
AuthBlockState state = {
.state =
ChallengeCredentialAuthBlockState{
.scrypt_state =
ScryptAuthBlockState{
.salt = kSalt,
.chaps_salt = kChapsSalt,
.reset_seed_salt = kResetSeedSalt,
.work_factor = kWorkFactor,
.block_size = kBlockSize,
.parallel_factor = kParallelFactor,
},
.keyset_challenge_info = structure::SignatureChallengeInfo{
.public_key_spki_der = BlobFromString("public_key_spki_der"),
.sealed_secret =
hwsec::Tpm12CertifiedMigratableKeyData{
.public_key_spki_der =
BlobFromString("public_key_spki_der"),
.srk_wrapped_cmk = BlobFromString("srk_wrapped_cmk"),
.cmk_pubkey = BlobFromString("cmk_pubkey"),
.cmk_wrapped_auth_data =
BlobFromString("cmk_wrapped_auth_data"),
.pcr_bound_items =
{
hwsec::Tpm12PcrBoundItem{
.pcr_values =
{
hwsec::Tpm12PcrValue{
.pcr_index = 4,
.pcr_value = BlobFromString(
"pcr_value1"),
},
},
.bound_secret =
BlobFromString("bound_secret0"),
},
hwsec::Tpm12PcrBoundItem{
.pcr_values =
{
hwsec::Tpm12PcrValue{
.pcr_index = 4,
.pcr_value =
BlobFromString(
"pcr_value1"),
},
},
.bound_secret = BlobFromString(
"bound_secret1"),
},
},
},
.salt = BlobFromString("salt"),
.salt_signature_algorithm = structure::
ChallengeSignatureAlgorithm::kRsassaPkcs1V15Sha256,
}}};
std::optional<SecureBlob> blob = state.Serialize();
ASSERT_TRUE(blob.has_value());
std::optional<AuthBlockState> state2 =
AuthBlockState::Deserialize(blob.value());
ASSERT_TRUE(state2.has_value());
EXPECT_EQ(state, state2);
}
TEST(AuthBlockStateBindingTest, ChallengeCredentialAuthBlockStateTpm2) {
AuthBlockState state = {
.state = ChallengeCredentialAuthBlockState{
.scrypt_state =
ScryptAuthBlockState{
.salt = kSalt,
.chaps_salt = kChapsSalt,
.reset_seed_salt = kResetSeedSalt,
.work_factor = kWorkFactor,
.block_size = kBlockSize,
.parallel_factor = kParallelFactor,
},
.keyset_challenge_info = structure::SignatureChallengeInfo{
.public_key_spki_der = BlobFromString("public_key_spki_der"),
.sealed_secret =
hwsec::Tpm2PolicySignedData{
.public_key_spki_der =
BlobFromString("public_key_spki_der"),
.srk_wrapped_secret =
BlobFromString("srk_wrapped_secret"),
.scheme = 5566,
.hash_alg = 7788,
.pcr_policy_digests =
{
hwsec::Tpm2PolicyDigest{
.digest = BlobFromString("digest0")},
hwsec::Tpm2PolicyDigest{
.digest = BlobFromString("digest1")},
},
},
.salt = BlobFromString("salt"),
.salt_signature_algorithm =
structure::ChallengeSignatureAlgorithm::kRsassaPkcs1V15Sha256,
}}};
std::optional<SecureBlob> blob = state.Serialize();
ASSERT_TRUE(blob.has_value());
std::optional<AuthBlockState> state2 =
AuthBlockState::Deserialize(blob.value());
ASSERT_TRUE(state2.has_value());
EXPECT_EQ(state, state2);
}
TEST(AuthBlockStateBindingTest, ChallengeCredentialAuthBlockStateEmpty) {
AuthBlockState state = {
.state = ChallengeCredentialAuthBlockState{
.scrypt_state =
ScryptAuthBlockState{
.salt = SecureBlob(""),
.chaps_salt = SecureBlob(""),
.reset_seed_salt = SecureBlob(""),
.work_factor = kWorkFactor,
.block_size = kBlockSize,
.parallel_factor = kParallelFactor,
},
.keyset_challenge_info = structure::SignatureChallengeInfo{
.public_key_spki_der = BlobFromString(""),
.sealed_secret =
hwsec::Tpm2PolicySignedData{
.public_key_spki_der = BlobFromString(""),
.srk_wrapped_secret = BlobFromString(""),
.pcr_policy_digests =
{
hwsec::Tpm2PolicyDigest{.digest =
BlobFromString("")},
hwsec::Tpm2PolicyDigest{.digest =
BlobFromString("")},
},
},
.salt = BlobFromString(""),
}}};
std::optional<SecureBlob> blob = state.Serialize();
ASSERT_TRUE(blob.has_value());
std::optional<AuthBlockState> state2 =
AuthBlockState::Deserialize(blob.value());
ASSERT_TRUE(state2.has_value());
EXPECT_EQ(state, state2);
}
TEST(AuthBlockStateBindingTest, ChallengeCredentialAuthBlockStateNoInfo) {
AuthBlockState state = {.state = ChallengeCredentialAuthBlockState{
.scrypt_state =
ScryptAuthBlockState{
.salt = kSalt,
.chaps_salt = kChapsSalt,
.reset_seed_salt = kResetSeedSalt,
.work_factor = kWorkFactor,
.block_size = kBlockSize,
.parallel_factor = kParallelFactor,
},
}};
std::optional<SecureBlob> blob = state.Serialize();
ASSERT_TRUE(blob.has_value());
std::optional<AuthBlockState> state2 =
AuthBlockState::Deserialize(blob.value());
ASSERT_TRUE(state2.has_value());
EXPECT_EQ(state, state2);
}
TEST(AuthBlockStateBindingTest, ChallengeCredentialAuthBlockStateDefault) {
AuthBlockState state = {
.state = ChallengeCredentialAuthBlockState{
.keyset_challenge_info = structure::SignatureChallengeInfo{
.sealed_secret = hwsec::Tpm2PolicySignedData{},
}}};
std::optional<SecureBlob> blob = state.Serialize();
ASSERT_TRUE(blob.has_value());
std::optional<AuthBlockState> state2 =
AuthBlockState::Deserialize(blob.value());
ASSERT_TRUE(state2.has_value());
EXPECT_EQ(state, state2);
state.state = ChallengeCredentialAuthBlockState{
.keyset_challenge_info = structure::SignatureChallengeInfo{
.public_key_spki_der = BlobFromString(""),
.sealed_secret =
hwsec::Tpm2PolicySignedData{
.public_key_spki_der = BlobFromString(""),
.srk_wrapped_secret = BlobFromString(""),
.pcr_policy_digests = {},
},
.salt = BlobFromString(""),
}};
EXPECT_EQ(state, state2);
}
TEST(AuthBlockStateBindingTest, TpmBoundToPcrAuthBlockState) {
AuthBlockState state = {
.state = TpmBoundToPcrAuthBlockState{
.scrypt_derived = false,
.salt = kSalt,
.tpm_key = SecureBlob("tpm_key"),
.extended_tpm_key = SecureBlob("extended_tpm_key"),
.tpm_public_key_hash = SecureBlob("tpm_public_key_hash"),
}};
std::optional<SecureBlob> blob = state.Serialize();
ASSERT_TRUE(blob.has_value());
std::optional<AuthBlockState> state2 =
AuthBlockState::Deserialize(blob.value());
ASSERT_TRUE(state2.has_value());
EXPECT_EQ(state, state2);
}
TEST(AuthBlockStateBindingTest, PinWeaverAuthBlockState) {
AuthBlockState state = {.state = PinWeaverAuthBlockState{
.le_label = 0x1337,
.salt = kSalt,
.chaps_iv = SecureBlob("chaps_iv"),
.fek_iv = SecureBlob("fek_iv"),
}};
std::optional<SecureBlob> blob = state.Serialize();
ASSERT_TRUE(blob.has_value());
std::optional<AuthBlockState> state2 =
AuthBlockState::Deserialize(blob.value());
ASSERT_TRUE(state2.has_value());
EXPECT_EQ(state, state2);
}
TEST(AuthBlockStateBindingTest, CryptohomeRecoveryAuthBlockState) {
AuthBlockState state = {.state = CryptohomeRecoveryAuthBlockState{
.hsm_payload = SecureBlob("hsm_payload"),
.encrypted_destination_share =
SecureBlob("encrypted_destination_share"),
.channel_pub_key = SecureBlob(),
.encrypted_channel_priv_key = SecureBlob(),
}};
std::optional<SecureBlob> blob = state.Serialize();
ASSERT_TRUE(blob.has_value());
std::optional<AuthBlockState> state2 =
AuthBlockState::Deserialize(blob.value());
ASSERT_TRUE(state2.has_value());
EXPECT_EQ(state, state2);
}
TEST(AuthBlockStateBindingTest, TpmEccAuthBlockState) {
AuthBlockState state = {
.state = TpmEccAuthBlockState{
.salt = kSalt,
.vkk_iv = SecureBlob("vkk_iv"),
.auth_value_rounds = 5,
.sealed_hvkkm = SecureBlob("sealed_hvkkm"),
.extended_sealed_hvkkm = SecureBlob("extended_sealed_hvkkm"),
.tpm_public_key_hash = std::nullopt,
.wrapped_reset_seed = SecureBlob("wrapped_reset_seed"),
}};
std::optional<SecureBlob> blob = state.Serialize();
ASSERT_TRUE(blob.has_value());
std::optional<AuthBlockState> state2 =
AuthBlockState::Deserialize(blob.value());
ASSERT_TRUE(state2.has_value());
EXPECT_EQ(state, state2);
}
} // namespace cryptohome