1 // Copyright 2021 Google LLC
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 #ifndef TINK_UTIL_SECRET_PROTO_H_
18 #define TINK_UTIL_SECRET_PROTO_H_
19
20 #include <memory>
21 #include <utility>
22
23 #include "google/protobuf/arena.h"
24 #include "absl/memory/memory.h"
25 #include "tink/util/secret_data.h"
26 #include "tink/util/status.h"
27 #include "tink/util/statusor.h"
28
29 namespace crypto {
30 namespace tink {
31 namespace util {
32
33 namespace internal {
34
SecretArenaOptions()35 inline google::protobuf::ArenaOptions SecretArenaOptions() {
36 google::protobuf::ArenaOptions options;
37 options.block_alloc = [](size_t sz) {
38 return SanitizingAllocator<void>().allocate(sz);
39 };
40 options.block_dealloc = [](void* ptr, size_t sz) {
41 return SanitizingAllocator<void>().deallocate(ptr, sz);
42 };
43 return options;
44 }
45
46 } // namespace internal
47
48 // Stores secret (sensitive) protobuf and makes sure it's marked as such and
49 // destroyed in a safe way.
50 //
51 // Note: Currently does not protect fields of type "string" and "bytes"
52 // (depends on https://github.com/protocolbuffers/protobuf/issues/1896)
53 template <typename T>
54 class SecretProto {
55 public:
ParseFromSecretData(const SecretData & data)56 static StatusOr<SecretProto<T>> ParseFromSecretData(const SecretData& data) {
57 SecretProto<T> proto;
58 if (!proto->ParseFromArray(data.data(), data.size())) {
59 return Status(absl::StatusCode::kInternal, "Could not parse proto");
60 }
61 return proto;
62 }
63
64 SecretProto() = default;
65
SecretProto(const SecretProto & other)66 SecretProto(const SecretProto& other) { *value_ = *other.value_; }
67
SecretProto(SecretProto && other)68 SecretProto(SecretProto&& other) { *this = std::move(other); }
69
SecretProto(const T & value)70 explicit SecretProto(const T& value) { *value_ = value; }
71
72 SecretProto& operator=(const SecretProto& other) {
73 *value_ = *other.value_;
74 return *this;
75 }
76
77 SecretProto& operator=(SecretProto&& other) {
78 using std::swap;
79 swap(arena_, other.arena_);
80 swap(value_, other.value_);
81 return *this;
82 }
83
get()84 inline T* get() { return value_; }
85
86 // Accessors to the underlying message.
87 inline T* operator->() { return value_; }
88 inline const T* operator->() const { return value_; }
89
90 inline T& operator*() { return *value_; }
91 inline const T& operator*() const { return *value_; }
92
SerializeAsSecretData()93 StatusOr<SecretData> SerializeAsSecretData() const {
94 SecretData data(value_->ByteSizeLong());
95 if (!value_->SerializeToArray(data.data(), data.size())) {
96 return Status(absl::StatusCode::kInternal, "Could not serialize proto");
97 }
98 return data;
99 }
100
101 private:
102 std::unique_ptr<google::protobuf::Arena> arena_ =
103 absl::make_unique<google::protobuf::Arena>(internal::SecretArenaOptions());
104 T* value_ = google::protobuf::Arena::CreateMessage<T>(arena_.get());
105 };
106
107 } // namespace util
108 } // namespace tink
109 } // namespace crypto
110
111 #endif // TINK_UTIL_SECRET_PROTO_H_
112