1 // Copyright 2017 Google Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15 ///////////////////////////////////////////////////////////////////////////////
16
17 #include "tink/mac/mac_wrapper.h"
18
19 #include <memory>
20 #include <string>
21 #include <utility>
22
23 #include "absl/status/status.h"
24 #include "absl/strings/str_cat.h"
25 #include "tink/crypto_format.h"
26 #include "tink/internal/monitoring_util.h"
27 #include "tink/internal/registry_impl.h"
28 #include "tink/internal/util.h"
29 #include "tink/mac.h"
30 #include "tink/monitoring/monitoring.h"
31 #include "tink/primitive_set.h"
32 #include "tink/util/status.h"
33 #include "tink/util/statusor.h"
34 #include "proto/tink.pb.h"
35
36 namespace crypto {
37 namespace tink {
38
39 using google::crypto::tink::OutputPrefixType;
40
41 namespace {
42
43 constexpr absl::string_view kPrimitive = "mac";
44 constexpr absl::string_view kComputeApi = "compute";
45 constexpr absl::string_view kVerifyApi = "verify";
46
47 class MacSetWrapper : public Mac {
48 public:
MacSetWrapper(std::unique_ptr<PrimitiveSet<Mac>> mac_set,std::unique_ptr<MonitoringClient> monitoring_compute_client=nullptr,std::unique_ptr<MonitoringClient> monitoring_verify_client=nullptr)49 explicit MacSetWrapper(
50 std::unique_ptr<PrimitiveSet<Mac>> mac_set,
51 std::unique_ptr<MonitoringClient> monitoring_compute_client = nullptr,
52 std::unique_ptr<MonitoringClient> monitoring_verify_client = nullptr)
53 : mac_set_(std::move(mac_set)),
54 monitoring_compute_client_(std::move(monitoring_compute_client)),
55 monitoring_verify_client_(std::move(monitoring_verify_client)) {}
56
57 crypto::tink::util::StatusOr<std::string> ComputeMac(
58 absl::string_view data) const override;
59
60 crypto::tink::util::Status VerifyMac(absl::string_view mac_value,
61 absl::string_view data) const override;
62
63 ~MacSetWrapper() override = default;
64
65 private:
66 std::unique_ptr<PrimitiveSet<Mac>> mac_set_;
67 std::unique_ptr<MonitoringClient> monitoring_compute_client_;
68 std::unique_ptr<MonitoringClient> monitoring_verify_client_;
69 };
70
Validate(PrimitiveSet<Mac> * mac_set)71 util::Status Validate(PrimitiveSet<Mac>* mac_set) {
72 if (mac_set == nullptr) {
73 return util::Status(absl::StatusCode::kInternal,
74 "mac_set must be non-NULL");
75 }
76 if (mac_set->get_primary() == nullptr) {
77 return util::Status(absl::StatusCode::kInvalidArgument,
78 "mac_set has no primary");
79 }
80 return util::OkStatus();
81 }
82
ComputeMac(absl::string_view data) const83 util::StatusOr<std::string> MacSetWrapper::ComputeMac(
84 absl::string_view data) const {
85 // BoringSSL expects a non-null pointer for data,
86 // regardless of whether the size is 0.
87 data = internal::EnsureStringNonNull(data);
88
89 auto primary = mac_set_->get_primary();
90 std::string local_data;
91 if (primary->get_output_prefix_type() == OutputPrefixType::LEGACY) {
92 local_data = std::string(data);
93 local_data.append(
94 reinterpret_cast<const char*>(&CryptoFormat::kLegacyStartByte), 1);
95 data = local_data;
96 }
97 auto compute_mac_result = primary->get_primitive().ComputeMac(data);
98 if (!compute_mac_result.ok()) {
99 if (monitoring_compute_client_ != nullptr) {
100 monitoring_compute_client_->LogFailure();
101 }
102 return compute_mac_result.status();
103 }
104 if (monitoring_compute_client_ != nullptr) {
105 monitoring_compute_client_->Log(mac_set_->get_primary()->get_key_id(),
106 data.size());
107 }
108 const std::string& key_id = primary->get_identifier();
109 return key_id + compute_mac_result.value();
110 }
111
VerifyMac(absl::string_view mac_value,absl::string_view data) const112 util::Status MacSetWrapper::VerifyMac(
113 absl::string_view mac_value,
114 absl::string_view data) const {
115 data = internal::EnsureStringNonNull(data);
116 mac_value = internal::EnsureStringNonNull(mac_value);
117
118 if (mac_value.length() > CryptoFormat::kNonRawPrefixSize) {
119 absl::string_view key_id =
120 mac_value.substr(0, CryptoFormat::kNonRawPrefixSize);
121 auto primitives_result = mac_set_->get_primitives(key_id);
122 if (primitives_result.ok()) {
123 absl::string_view raw_mac_value =
124 mac_value.substr(CryptoFormat::kNonRawPrefixSize);
125 for (auto& mac_entry : *(primitives_result.value())) {
126 std::string legacy_data;
127 absl::string_view view_on_data_or_legacy_data = data;
128 if (mac_entry->get_output_prefix_type() == OutputPrefixType::LEGACY) {
129 legacy_data = absl::StrCat(data, std::string("\x00", 1));
130 view_on_data_or_legacy_data = legacy_data;
131 }
132 Mac& mac = mac_entry->get_primitive();
133 util::Status status =
134 mac.VerifyMac(raw_mac_value, view_on_data_or_legacy_data);
135 if (status.ok()) {
136 if (monitoring_verify_client_ != nullptr) {
137 monitoring_verify_client_->Log(mac_entry->get_key_id(),
138 data.size());
139 }
140 return status;
141 } else {
142 // TODO(przydatek): LOG that a matching key didn't verify the MAC.
143 }
144 }
145 }
146 }
147
148 // No matching key succeeded with verification, try all RAW keys.
149 auto raw_primitives_result = mac_set_->get_raw_primitives();
150 if (raw_primitives_result.ok()) {
151 for (auto& mac_entry : *(raw_primitives_result.value())) {
152 Mac& mac = mac_entry->get_primitive();
153 util::Status status = mac.VerifyMac(mac_value, data);
154 if (status.ok()) {
155 if (monitoring_verify_client_ != nullptr) {
156 monitoring_verify_client_->Log(mac_entry->get_key_id(), data.size());
157 }
158 return status;
159 }
160 }
161 }
162 if (monitoring_verify_client_ != nullptr) {
163 monitoring_verify_client_->LogFailure();
164 }
165
166 return util::Status(absl::StatusCode::kInvalidArgument,
167 "verification failed");
168 }
169
170 } // namespace
171
Wrap(std::unique_ptr<PrimitiveSet<Mac>> mac_set) const172 util::StatusOr<std::unique_ptr<Mac>> MacWrapper::Wrap(
173 std::unique_ptr<PrimitiveSet<Mac>> mac_set) const {
174 util::Status status = Validate(mac_set.get());
175 if (!status.ok()) return status;
176
177 MonitoringClientFactory* const monitoring_factory =
178 internal::RegistryImpl::GlobalInstance().GetMonitoringClientFactory();
179
180 // Monitoring is not enabled. Create a wrapper without monitoring clients.
181 if (monitoring_factory == nullptr) {
182 return {absl::make_unique<MacSetWrapper>(std::move(mac_set))};
183 }
184
185 util::StatusOr<MonitoringKeySetInfo> keyset_info =
186 internal::MonitoringKeySetInfoFromPrimitiveSet(*mac_set);
187 if (!keyset_info.ok()) {
188 return keyset_info.status();
189 }
190
191 util::StatusOr<std::unique_ptr<MonitoringClient>> monitoring_compute_client =
192 monitoring_factory->New(
193 MonitoringContext(kPrimitive, kComputeApi, *keyset_info));
194 if (!monitoring_compute_client.ok()) {
195 return monitoring_compute_client.status();
196 }
197
198 util::StatusOr<std::unique_ptr<MonitoringClient>> monitoring_verify_client =
199 monitoring_factory->New(
200 MonitoringContext(kPrimitive, kVerifyApi, *keyset_info));
201 if (!monitoring_verify_client.ok()) {
202 return monitoring_verify_client.status();
203 }
204
205 return {absl::make_unique<MacSetWrapper>(
206 std::move(mac_set), *std::move(monitoring_compute_client),
207 *std::move(monitoring_verify_client))};
208 }
209
210 } // namespace tink
211 } // namespace crypto
212