blob: 2332b41e177b0da134fbd6aedcf3d3057f8b5b3d [file] [log] [blame]
// Copyright 2015 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "trunks/policy_session_impl.h"
#include <map>
#include <string>
#include <vector>
#include <base/check.h>
#include <base/logging.h>
#include <base/macros.h>
#include <base/stl_util.h>
#include <crypto/sha2.h>
#include <openssl/rand.h>
#include "trunks/error_codes.h"
#include "trunks/tpm_generated.h"
namespace trunks {
PolicySessionImpl::PolicySessionImpl(const TrunksFactory& factory)
: factory_(factory), session_type_(TPM_SE_POLICY) {
session_manager_ = factory_.GetSessionManager();
}
PolicySessionImpl::PolicySessionImpl(const TrunksFactory& factory,
TPM_SE session_type)
: factory_(factory), session_type_(session_type) {
session_manager_ = factory_.GetSessionManager();
}
PolicySessionImpl::~PolicySessionImpl() {
session_manager_->CloseSession();
}
AuthorizationDelegate* PolicySessionImpl::GetDelegate() {
if (session_manager_->GetSessionHandle() == kUninitializedHandle) {
return nullptr;
}
return &hmac_delegate_;
}
TPM_RC PolicySessionImpl::StartBoundSession(
TPMI_DH_ENTITY bind_entity,
const std::string& bind_authorization_value,
bool salted,
bool enable_encryption) {
hmac_delegate_.set_use_entity_authorization_for_encryption_only(true);
if (session_type_ != TPM_SE_POLICY && session_type_ != TPM_SE_TRIAL) {
LOG(ERROR) << "Cannot start a session of that type.";
return SAPI_RC_INVALID_SESSIONS;
}
return session_manager_->StartSession(session_type_, bind_entity,
bind_authorization_value, salted,
enable_encryption, &hmac_delegate_);
}
TPM_RC PolicySessionImpl::StartUnboundSession(bool salted,
bool enable_encryption) {
// Just like a HmacAuthorizationSession, an unbound policy session is just
// a session bound to TPM_RH_NULL.
return StartBoundSession(TPM_RH_NULL, "", salted, enable_encryption);
}
TPM_RC PolicySessionImpl::GetDigest(std::string* digest) {
CHECK(digest);
TPM2B_DIGEST policy_digest;
TPM_RC result = factory_.GetTpm()->PolicyGetDigestSync(
session_manager_->GetSessionHandle(),
"", // No name is needed for this command, as it does no authorization.
&policy_digest, nullptr);
if (result != TPM_RC_SUCCESS) {
LOG(ERROR) << "Error getting policy digest: " << GetErrorString(result);
return result;
}
*digest = StringFrom_TPM2B_DIGEST(policy_digest);
return TPM_RC_SUCCESS;
}
TPM_RC PolicySessionImpl::PolicyOR(const std::vector<std::string>& digests) {
TPML_DIGEST tpm_digests;
if (digests.size() >= base::size(tpm_digests.digests)) {
LOG(ERROR) << "TPM2.0 Spec only allows for up to 8 digests.";
return SAPI_RC_BAD_PARAMETER;
}
tpm_digests.count = digests.size();
for (size_t i = 0; i < digests.size(); i++) {
tpm_digests.digests[i] = Make_TPM2B_DIGEST(digests[i]);
}
TPM_RC result = factory_.GetTpm()->PolicyORSync(
session_manager_->GetSessionHandle(),
"", // No policy name is needed as we do no authorization checks.
tpm_digests, nullptr);
if (result != TPM_RC_SUCCESS) {
LOG(ERROR) << "Error performing PolicyOR: " << GetErrorString(result);
return result;
}
return TPM_RC_SUCCESS;
}
TPM_RC PolicySessionImpl::PolicyPCR(
const std::map<uint32_t, std::string>& pcr_map) {
TPML_PCR_SELECTION pcr_select;
memset(&pcr_select, 0, sizeof(TPML_PCR_SELECTION));
// This process of selecting pcrs is highlighted in TPM 2.0 Library Spec
// Part 2 (Section 10.5 - PCR structures).
pcr_select.count = 1;
pcr_select.pcr_selections[0].hash = TPM_ALG_SHA256;
pcr_select.pcr_selections[0].sizeof_select = PCR_SELECT_MIN;
TPM2B_DIGEST pcr_digest;
std::string concatenated_pcr_values;
bool map_contains_empty_value = false;
for (const auto& map_pair : pcr_map) {
uint32_t pcr_index = map_pair.first;
const std::string& pcr_value = map_pair.second;
if (pcr_value.empty()) {
map_contains_empty_value = true;
}
uint8_t pcr_select_index = pcr_index / 8;
uint8_t pcr_select_byte = 1 << (pcr_index % 8);
if (pcr_select_index >= PCR_SELECT_MIN) {
LOG(ERROR) << "Out of bounds pcr_index provided: " << pcr_index;
return SAPI_RC_BAD_PARAMETER;
}
pcr_select.pcr_selections[0].pcr_select[pcr_select_index] |=
pcr_select_byte;
concatenated_pcr_values += pcr_value;
}
if (concatenated_pcr_values.empty()) {
if (session_type_ == TPM_SE_TRIAL) {
LOG(ERROR) << "Trial sessions have to define a PCR value.";
return SAPI_RC_BAD_PARAMETER;
}
pcr_digest = Make_TPM2B_DIGEST("");
} else {
if (map_contains_empty_value) {
LOG(ERROR) << "PCR map must not have both empty and non-empty values.";
return SAPI_RC_BAD_PARAMETER;
}
pcr_digest =
Make_TPM2B_DIGEST(crypto::SHA256HashString(concatenated_pcr_values));
}
TPM_RC result = factory_.GetTpm()->PolicyPCRSync(
session_manager_->GetSessionHandle(),
"", // No policy name is needed as we do no authorization checks.
pcr_digest, pcr_select, nullptr);
if (result != TPM_RC_SUCCESS) {
LOG(ERROR) << "Error performing PolicyPCR: " << GetErrorString(result);
return result;
}
return TPM_RC_SUCCESS;
}
TPM_RC PolicySessionImpl::PolicyCommandCode(TPM_CC command_code) {
TPM_RC result = factory_.GetTpm()->PolicyCommandCodeSync(
session_manager_->GetSessionHandle(),
"", // No policy name is needed as we do no authorization checks.
command_code, nullptr);
if (result != TPM_RC_SUCCESS) {
LOG(ERROR) << "Error performing PolicyCommandCode: "
<< GetErrorString(result);
return result;
}
return TPM_RC_SUCCESS;
}
TPM_RC PolicySessionImpl::PolicySecret(TPMI_DH_ENTITY auth_entity,
const std::string& auth_entity_name,
const std::string& nonce,
const std::string& cp_hash,
const std::string& policy_ref,
int32_t expiration,
AuthorizationDelegate* delegate) {
TPM2B_TIMEOUT timeout;
TPMT_TK_AUTH policy_ticket;
TPM_HANDLE policy_session_handle = session_manager_->GetSessionHandle();
std::string policy_session_name;
trunks::Serialize_TPM_HANDLE(policy_session_handle, &policy_session_name);
TPM_RC result = factory_.GetTpm()->PolicySecretSync(
auth_entity, auth_entity_name, policy_session_handle, policy_session_name,
Make_TPM2B_DIGEST(nonce), Make_TPM2B_DIGEST(cp_hash),
Make_TPM2B_DIGEST(policy_ref), expiration, &timeout, &policy_ticket,
delegate);
if (result != TPM_RC_SUCCESS) {
LOG(ERROR) << "Error performing PolicySecret: " << GetErrorString(result);
return result;
}
return TPM_RC_SUCCESS;
}
TPM_RC PolicySessionImpl::PolicySigned(TPMI_DH_ENTITY auth_entity,
const std::string& auth_entity_name,
const std::string& nonce,
const std::string& cp_hash,
const std::string& policy_ref,
int32_t expiration,
const trunks::TPMT_SIGNATURE& signature,
AuthorizationDelegate* delegate) {
TPM2B_TIMEOUT timeout;
TPMT_TK_AUTH policy_ticket;
TPM_HANDLE policy_session_handle = session_manager_->GetSessionHandle();
std::string policy_session_name;
trunks::Serialize_TPM_HANDLE(policy_session_handle, &policy_session_name);
TPM_RC result = factory_.GetTpm()->PolicySignedSync(
auth_entity, auth_entity_name, policy_session_handle, policy_session_name,
Make_TPM2B_DIGEST(nonce), Make_TPM2B_DIGEST(cp_hash),
Make_TPM2B_DIGEST(policy_ref), expiration, signature, &timeout,
&policy_ticket, delegate);
if (result != TPM_RC_SUCCESS) {
LOG(ERROR) << "Error performing PolicySigned: " << GetErrorString(result);
return result;
}
return TPM_RC_SUCCESS;
}
TPM_RC PolicySessionImpl::PolicyAuthValue() {
TPM_RC result = factory_.GetTpm()->PolicyAuthValueSync(
session_manager_->GetSessionHandle(),
"", // No policy name is needed as we do no authorization checks.
nullptr);
if (result != TPM_RC_SUCCESS) {
LOG(ERROR) << "Error performing PolicyAuthValue: "
<< GetErrorString(result);
return result;
}
hmac_delegate_.set_use_entity_authorization_for_encryption_only(false);
return TPM_RC_SUCCESS;
}
TPM_RC PolicySessionImpl::PolicyRestart() {
TPM_RC result = factory_.GetTpm()->PolicyAuthValueSync(
session_manager_->GetSessionHandle(),
"", // No policy name is needed as we do no authorization checks.
nullptr);
if (result != TPM_RC_SUCCESS) {
LOG(ERROR) << "Error performing PolicyRestart: " << GetErrorString(result);
return result;
}
return TPM_RC_SUCCESS;
}
void PolicySessionImpl::SetEntityAuthorizationValue(const std::string& value) {
hmac_delegate_.set_entity_authorization_value(value);
}
TPM_RC PolicySessionImpl::PolicyFidoSigned(
TPMI_DH_ENTITY auth_entity,
const std::string& auth_entity_name,
const std::string& auth_data,
const std::vector<FIDO_DATA_RANGE>& auth_data_descr,
const TPMT_SIGNATURE& signature,
AuthorizationDelegate* delegate) {
TPM_HANDLE policy_session_handle = session_manager_->GetSessionHandle();
std::string policy_session_name;
Serialize_TPM_HANDLE(policy_session_handle, &policy_session_name);
TPM_RC result = factory_.GetTpm()->PolicyFidoSignedSync(
auth_entity, auth_entity_name, policy_session_handle, policy_session_name,
auth_data, auth_data_descr, signature, delegate);
if (result != TPM_RC_SUCCESS) {
LOG(ERROR) << "Error performing PolicyFidoSigned: "
<< GetErrorString(result);
return result;
}
return TPM_RC_SUCCESS;
}
} // namespace trunks