1//
2// Copyright (C) 2015 The Android Open Source Project
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8//      http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
16
17#include "trunks/policy_session_impl.h"
18
19#include <string>
20#include <vector>
21
22#include <base/logging.h>
23#include <base/macros.h>
24#include <base/stl_util.h>
25#include <crypto/sha2.h>
26#include <openssl/rand.h>
27
28#include "trunks/error_codes.h"
29#include "trunks/tpm_generated.h"
30
31namespace trunks {
32
33PolicySessionImpl::PolicySessionImpl(const TrunksFactory& factory)
34    : factory_(factory),
35      session_type_(TPM_SE_POLICY) {
36  session_manager_ = factory_.GetSessionManager();
37}
38
39PolicySessionImpl::PolicySessionImpl(const TrunksFactory& factory,
40                                     TPM_SE session_type)
41    : factory_(factory),
42      session_type_(session_type) {
43  session_manager_ = factory_.GetSessionManager();
44}
45
46PolicySessionImpl::~PolicySessionImpl() {
47  session_manager_->CloseSession();
48}
49
50AuthorizationDelegate* PolicySessionImpl::GetDelegate() {
51  if (session_manager_->GetSessionHandle() == kUninitializedHandle) {
52    return nullptr;
53  }
54  return &hmac_delegate_;
55}
56
57TPM_RC PolicySessionImpl::StartBoundSession(
58    TPMI_DH_ENTITY bind_entity,
59    const std::string& bind_authorization_value,
60    bool enable_encryption) {
61  hmac_delegate_.set_use_entity_authorization_for_encryption_only(true);
62  if (session_type_ != TPM_SE_POLICY && session_type_ != TPM_SE_TRIAL) {
63    LOG(ERROR) << "Cannot start a session of that type.";
64    return SAPI_RC_INVALID_SESSIONS;
65  }
66  return session_manager_->StartSession(session_type_, bind_entity,
67                                        bind_authorization_value,
68                                        enable_encryption, &hmac_delegate_);
69}
70
71TPM_RC PolicySessionImpl::StartUnboundSession(bool enable_encryption) {
72  // Just like a HmacAuthorizationSession, an unbound policy session is just
73  // a session bound to TPM_RH_NULL.
74  return StartBoundSession(TPM_RH_NULL, "", enable_encryption);
75}
76
77TPM_RC PolicySessionImpl::GetDigest(std::string* digest) {
78  CHECK(digest);
79  TPM2B_DIGEST policy_digest;
80  TPM_RC result = factory_.GetTpm()->PolicyGetDigestSync(
81      session_manager_->GetSessionHandle(),
82      "",  // No name is needed for this command, as it does no authorization.
83      &policy_digest,
84      nullptr);
85  if (result != TPM_RC_SUCCESS) {
86    LOG(ERROR) << "Error getting policy digest: " << GetErrorString(result);
87    return result;
88  }
89  *digest = StringFrom_TPM2B_DIGEST(policy_digest);
90  return TPM_RC_SUCCESS;
91}
92
93TPM_RC PolicySessionImpl::PolicyOR(const std::vector<std::string>& digests) {
94  if (digests.size() >= arraysize(TPML_DIGEST::digests)) {
95    LOG(ERROR) << "TPM2.0 Spec only allows for up to 8 digests.";
96    return SAPI_RC_BAD_PARAMETER;
97  }
98  TPML_DIGEST tpm_digests;
99  tpm_digests.count = digests.size();
100  for (size_t i = 0; i < digests.size(); i++) {
101    tpm_digests.digests[i] = Make_TPM2B_DIGEST(digests[i]);
102  }
103  TPM_RC result = factory_.GetTpm()->PolicyORSync(
104      session_manager_->GetSessionHandle(),
105      "",  // No policy name is needed as we do no authorization checks.
106      tpm_digests,
107      nullptr);
108  if (result != TPM_RC_SUCCESS) {
109    LOG(ERROR) << "Error performing PolicyOR: " << GetErrorString(result);
110    return result;
111  }
112
113  return TPM_RC_SUCCESS;
114}
115
116TPM_RC PolicySessionImpl::PolicyPCR(uint32_t pcr_index,
117                                    const std::string& pcr_value) {
118  TPML_PCR_SELECTION pcr_select;
119  memset(&pcr_select, 0, sizeof(TPML_PCR_SELECTION));
120  // This process of selecting pcrs is highlighted in TPM 2.0 Library Spec
121  // Part 2 (Section 10.5 - PCR structures).
122  uint8_t pcr_select_index = pcr_index / 8;
123  uint8_t pcr_select_byte = 1 << (pcr_index % 8);
124  pcr_select.count = 1;
125  pcr_select.pcr_selections[0].hash = TPM_ALG_SHA256;
126  pcr_select.pcr_selections[0].sizeof_select = PCR_SELECT_MIN;
127  pcr_select.pcr_selections[0].pcr_select[pcr_select_index] = pcr_select_byte;
128  TPM2B_DIGEST pcr_digest;
129  if (pcr_value.empty()) {
130    if (session_type_ == TPM_SE_TRIAL) {
131      LOG(ERROR) << "Trial sessions have to define a PCR value.";
132      return SAPI_RC_BAD_PARAMETER;
133    }
134    pcr_digest = Make_TPM2B_DIGEST("");
135  } else {
136    pcr_digest = Make_TPM2B_DIGEST(crypto::SHA256HashString(pcr_value));
137  }
138
139  TPM_RC result = factory_.GetTpm()->PolicyPCRSync(
140      session_manager_->GetSessionHandle(),
141      "",  // No policy name is needed as we do no authorization checks.
142      pcr_digest,
143      pcr_select,
144      nullptr);
145  if (result != TPM_RC_SUCCESS) {
146    LOG(ERROR) << "Error performing PolicyPCR: " << GetErrorString(result);
147    return result;
148  }
149  return TPM_RC_SUCCESS;
150}
151
152TPM_RC PolicySessionImpl::PolicyCommandCode(TPM_CC command_code) {
153  TPM_RC result = factory_.GetTpm()->PolicyCommandCodeSync(
154      session_manager_->GetSessionHandle(),
155      "",  // No policy name is needed as we do no authorization checks.
156      command_code,
157      nullptr);
158  if (result != TPM_RC_SUCCESS) {
159    LOG(ERROR) << "Error performing PolicyCommandCode: "
160               << GetErrorString(result);
161    return result;
162  }
163  return TPM_RC_SUCCESS;
164}
165
166TPM_RC PolicySessionImpl::PolicyAuthValue() {
167  TPM_RC result = factory_.GetTpm()->PolicyAuthValueSync(
168      session_manager_->GetSessionHandle(),
169      "",  // No policy name is needed as we do no authorization checks.
170      nullptr);
171  if (result != TPM_RC_SUCCESS) {
172    LOG(ERROR) << "Error performing PolicyAuthValue: "
173               << GetErrorString(result);
174    return result;
175  }
176  hmac_delegate_.set_use_entity_authorization_for_encryption_only(false);
177  return TPM_RC_SUCCESS;
178}
179
180void PolicySessionImpl::SetEntityAuthorizationValue(const std::string& value) {
181  hmac_delegate_.set_entity_authorization_value(value);
182}
183
184}  // namespace trunks
185