xref: /aosp_15_r20/external/tink/cc/mac/mac_wrapper.cc (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
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