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/signature/public_key_sign_wrapper.h"
18
19 #include <memory>
20 #include <string>
21 #include <utility>
22
23 #include "absl/status/status.h"
24 #include "tink/crypto_format.h"
25 #include "tink/internal/monitoring_util.h"
26 #include "tink/internal/registry_impl.h"
27 #include "tink/internal/util.h"
28 #include "tink/monitoring/monitoring.h"
29 #include "tink/primitive_set.h"
30 #include "tink/public_key_sign.h"
31 #include "tink/util/statusor.h"
32 #include "proto/tink.pb.h"
33
34 namespace crypto {
35 namespace tink {
36
37 using google::crypto::tink::OutputPrefixType;
38
39 namespace {
40
41 constexpr absl::string_view kPrimitive = "public_key_sign";
42 constexpr absl::string_view kSignApi = "sign";
43
Validate(PrimitiveSet<PublicKeySign> * public_key_sign_set)44 util::Status Validate(PrimitiveSet<PublicKeySign>* public_key_sign_set) {
45 if (public_key_sign_set == nullptr) {
46 return util::Status(absl::StatusCode::kInternal,
47 "public_key_sign_set must be non-NULL");
48 }
49 if (public_key_sign_set->get_primary() == nullptr) {
50 return util::Status(absl::StatusCode::kInvalidArgument,
51 "public_key_sign_set has no primary");
52 }
53 return util::OkStatus();
54 }
55
56 class PublicKeySignSetWrapper : public PublicKeySign {
57 public:
PublicKeySignSetWrapper(std::unique_ptr<PrimitiveSet<PublicKeySign>> public_key_sign_set,std::unique_ptr<MonitoringClient> monitoring_sign_client=nullptr)58 explicit PublicKeySignSetWrapper(
59 std::unique_ptr<PrimitiveSet<PublicKeySign>> public_key_sign_set,
60 std::unique_ptr<MonitoringClient> monitoring_sign_client = nullptr)
61 : public_key_sign_set_(std::move(public_key_sign_set)),
62 monitoring_sign_client_(std::move(monitoring_sign_client)) {}
63
64 crypto::tink::util::StatusOr<std::string> Sign(
65 absl::string_view data) const override;
66
67 ~PublicKeySignSetWrapper() override = default;
68
69 private:
70 std::unique_ptr<PrimitiveSet<PublicKeySign>> public_key_sign_set_;
71 std::unique_ptr<MonitoringClient> monitoring_sign_client_;
72 };
73
Sign(absl::string_view data) const74 util::StatusOr<std::string> PublicKeySignSetWrapper::Sign(
75 absl::string_view data) const {
76 // BoringSSL expects a non-null pointer for data,
77 // regardless of whether the size is 0.
78 data = internal::EnsureStringNonNull(data);
79
80 auto primary = public_key_sign_set_->get_primary();
81 std::string local_data;
82 if (primary->get_output_prefix_type() == OutputPrefixType::LEGACY) {
83 local_data = std::string(data);
84 local_data.append(1, CryptoFormat::kLegacyStartByte);
85 data = local_data;
86 }
87 auto sign_result = primary->get_primitive().Sign(data);
88 if (!sign_result.ok()) {
89 if (monitoring_sign_client_ != nullptr) {
90 monitoring_sign_client_->LogFailure();
91 }
92 return sign_result.status();
93 }
94 if (monitoring_sign_client_ != nullptr) {
95 monitoring_sign_client_->Log(
96 public_key_sign_set_->get_primary()->get_key_id(), data.size());
97 }
98 const std::string& key_id = primary->get_identifier();
99 return key_id + sign_result.value();
100 }
101
102 } // anonymous namespace
103
Wrap(std::unique_ptr<PrimitiveSet<PublicKeySign>> primitive_set) const104 util::StatusOr<std::unique_ptr<PublicKeySign>> PublicKeySignWrapper::Wrap(
105 std::unique_ptr<PrimitiveSet<PublicKeySign>> primitive_set) const {
106 util::Status status = Validate(primitive_set.get());
107 if (!status.ok()) return status;
108
109 MonitoringClientFactory* const monitoring_factory =
110 internal::RegistryImpl::GlobalInstance().GetMonitoringClientFactory();
111
112 // Monitoring is not enabled. Create a wrapper without monitoring clients.
113 if (monitoring_factory == nullptr) {
114 return {
115 absl::make_unique<PublicKeySignSetWrapper>(std::move(primitive_set))};
116 }
117
118 util::StatusOr<MonitoringKeySetInfo> keyset_info =
119 internal::MonitoringKeySetInfoFromPrimitiveSet(*primitive_set);
120 if (!keyset_info.ok()) {
121 return keyset_info.status();
122 }
123
124 util::StatusOr<std::unique_ptr<MonitoringClient>> monitoring_sign_client =
125 monitoring_factory->New(
126 MonitoringContext(kPrimitive, kSignApi, *keyset_info));
127 if (!monitoring_sign_client.ok()) {
128 return monitoring_sign_client.status();
129 }
130
131 return {absl::make_unique<PublicKeySignSetWrapper>(
132 std::move(primitive_set), *std::move(monitoring_sign_client))};
133 }
134
135 } // namespace tink
136 } // namespace crypto
137