1 /*
2 *
3 * Copyright 2018 gRPC authors.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 */
18
19 #include <grpc/support/port_platform.h>
20
21 #include "src/core/lib/security/security_connector/alts/alts_security_connector.h"
22
23 #include <stdbool.h>
24 #include <string.h>
25
26 #include <grpc/grpc.h>
27 #include <grpc/support/alloc.h>
28 #include <grpc/support/log.h>
29 #include <grpc/support/string_util.h>
30
31 #include "src/core/lib/gprpp/ref_counted_ptr.h"
32 #include "src/core/lib/security/credentials/alts/alts_credentials.h"
33 #include "src/core/lib/security/transport/security_handshaker.h"
34 #include "src/core/lib/slice/slice_internal.h"
35 #include "src/core/lib/transport/transport.h"
36 #include "src/core/tsi/alts/handshaker/alts_tsi_handshaker.h"
37 #include "src/core/tsi/transport_security.h"
38
grpc_alts_set_rpc_protocol_versions(grpc_gcp_rpc_protocol_versions * rpc_versions)39 void grpc_alts_set_rpc_protocol_versions(
40 grpc_gcp_rpc_protocol_versions* rpc_versions) {
41 grpc_gcp_rpc_protocol_versions_set_max(rpc_versions,
42 GRPC_PROTOCOL_VERSION_MAX_MAJOR,
43 GRPC_PROTOCOL_VERSION_MAX_MINOR);
44 grpc_gcp_rpc_protocol_versions_set_min(rpc_versions,
45 GRPC_PROTOCOL_VERSION_MIN_MAJOR,
46 GRPC_PROTOCOL_VERSION_MIN_MINOR);
47 }
48
49 namespace {
50
alts_check_peer(tsi_peer peer,grpc_core::RefCountedPtr<grpc_auth_context> * auth_context,grpc_closure * on_peer_checked)51 void alts_check_peer(tsi_peer peer,
52 grpc_core::RefCountedPtr<grpc_auth_context>* auth_context,
53 grpc_closure* on_peer_checked) {
54 *auth_context =
55 grpc_core::internal::grpc_alts_auth_context_from_tsi_peer(&peer);
56 tsi_peer_destruct(&peer);
57 grpc_error* error =
58 *auth_context != nullptr
59 ? GRPC_ERROR_NONE
60 : GRPC_ERROR_CREATE_FROM_STATIC_STRING(
61 "Could not get ALTS auth context from TSI peer");
62 grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_peer_checked, error);
63 }
64
65 class grpc_alts_channel_security_connector final
66 : public grpc_channel_security_connector {
67 public:
grpc_alts_channel_security_connector(grpc_core::RefCountedPtr<grpc_channel_credentials> channel_creds,grpc_core::RefCountedPtr<grpc_call_credentials> request_metadata_creds,const char * target_name)68 grpc_alts_channel_security_connector(
69 grpc_core::RefCountedPtr<grpc_channel_credentials> channel_creds,
70 grpc_core::RefCountedPtr<grpc_call_credentials> request_metadata_creds,
71 const char* target_name)
72 : grpc_channel_security_connector(GRPC_ALTS_URL_SCHEME,
73 std::move(channel_creds),
74 std::move(request_metadata_creds)),
75 target_name_(gpr_strdup(target_name)) {}
76
~grpc_alts_channel_security_connector()77 ~grpc_alts_channel_security_connector() override { gpr_free(target_name_); }
78
add_handshakers(const grpc_channel_args * args,grpc_pollset_set * interested_parties,grpc_core::HandshakeManager * handshake_manager)79 void add_handshakers(
80 const grpc_channel_args* args, grpc_pollset_set* interested_parties,
81 grpc_core::HandshakeManager* handshake_manager) override {
82 tsi_handshaker* handshaker = nullptr;
83 const grpc_alts_credentials* creds =
84 static_cast<const grpc_alts_credentials*>(channel_creds());
85 size_t user_specified_max_frame_size = 0;
86 const grpc_arg* arg =
87 grpc_channel_args_find(args, GRPC_ARG_TSI_MAX_FRAME_SIZE);
88 if (arg != nullptr && arg->type == GRPC_ARG_INTEGER) {
89 user_specified_max_frame_size = grpc_channel_arg_get_integer(
90 arg, {0, 0, std::numeric_limits<int>::max()});
91 }
92 GPR_ASSERT(alts_tsi_handshaker_create(
93 creds->options(), target_name_,
94 creds->handshaker_service_url(), true, interested_parties,
95 &handshaker, user_specified_max_frame_size) == TSI_OK);
96 handshake_manager->Add(
97 grpc_core::SecurityHandshakerCreate(handshaker, this, args));
98 }
99
check_peer(tsi_peer peer,grpc_endpoint *,grpc_core::RefCountedPtr<grpc_auth_context> * auth_context,grpc_closure * on_peer_checked)100 void check_peer(tsi_peer peer, grpc_endpoint* /*ep*/,
101 grpc_core::RefCountedPtr<grpc_auth_context>* auth_context,
102 grpc_closure* on_peer_checked) override {
103 alts_check_peer(peer, auth_context, on_peer_checked);
104 }
105
cmp(const grpc_security_connector * other_sc) const106 int cmp(const grpc_security_connector* other_sc) const override {
107 auto* other =
108 reinterpret_cast<const grpc_alts_channel_security_connector*>(other_sc);
109 int c = channel_security_connector_cmp(other);
110 if (c != 0) return c;
111 return strcmp(target_name_, other->target_name_);
112 }
113
check_call_host(absl::string_view host,grpc_auth_context *,grpc_closure *,grpc_error ** error)114 bool check_call_host(absl::string_view host,
115 grpc_auth_context* /*auth_context*/,
116 grpc_closure* /*on_call_host_checked*/,
117 grpc_error** error) override {
118 if (host.empty() || host != target_name_) {
119 *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
120 "ALTS call host does not match target name");
121 }
122 return true;
123 }
124
cancel_check_call_host(grpc_closure *,grpc_error * error)125 void cancel_check_call_host(grpc_closure* /*on_call_host_checked*/,
126 grpc_error* error) override {
127 GRPC_ERROR_UNREF(error);
128 }
129
130 private:
131 char* target_name_;
132 };
133
134 class grpc_alts_server_security_connector final
135 : public grpc_server_security_connector {
136 public:
grpc_alts_server_security_connector(grpc_core::RefCountedPtr<grpc_server_credentials> server_creds)137 explicit grpc_alts_server_security_connector(
138 grpc_core::RefCountedPtr<grpc_server_credentials> server_creds)
139 : grpc_server_security_connector(GRPC_ALTS_URL_SCHEME,
140 std::move(server_creds)) {}
141
142 ~grpc_alts_server_security_connector() override = default;
143
add_handshakers(const grpc_channel_args * args,grpc_pollset_set * interested_parties,grpc_core::HandshakeManager * handshake_manager)144 void add_handshakers(
145 const grpc_channel_args* args, grpc_pollset_set* interested_parties,
146 grpc_core::HandshakeManager* handshake_manager) override {
147 tsi_handshaker* handshaker = nullptr;
148 const grpc_alts_server_credentials* creds =
149 static_cast<const grpc_alts_server_credentials*>(server_creds());
150 size_t user_specified_max_frame_size = 0;
151 const grpc_arg* arg =
152 grpc_channel_args_find(args, GRPC_ARG_TSI_MAX_FRAME_SIZE);
153 if (arg != nullptr && arg->type == GRPC_ARG_INTEGER) {
154 user_specified_max_frame_size = grpc_channel_arg_get_integer(
155 arg, {0, 0, std::numeric_limits<int>::max()});
156 }
157 GPR_ASSERT(alts_tsi_handshaker_create(
158 creds->options(), nullptr, creds->handshaker_service_url(),
159 false, interested_parties, &handshaker,
160 user_specified_max_frame_size) == TSI_OK);
161 handshake_manager->Add(
162 grpc_core::SecurityHandshakerCreate(handshaker, this, args));
163 }
164
check_peer(tsi_peer peer,grpc_endpoint *,grpc_core::RefCountedPtr<grpc_auth_context> * auth_context,grpc_closure * on_peer_checked)165 void check_peer(tsi_peer peer, grpc_endpoint* /*ep*/,
166 grpc_core::RefCountedPtr<grpc_auth_context>* auth_context,
167 grpc_closure* on_peer_checked) override {
168 alts_check_peer(peer, auth_context, on_peer_checked);
169 }
170
cmp(const grpc_security_connector * other) const171 int cmp(const grpc_security_connector* other) const override {
172 return server_security_connector_cmp(
173 static_cast<const grpc_server_security_connector*>(other));
174 }
175 };
176 } // namespace
177
178 namespace grpc_core {
179 namespace internal {
180 grpc_core::RefCountedPtr<grpc_auth_context>
grpc_alts_auth_context_from_tsi_peer(const tsi_peer * peer)181 grpc_alts_auth_context_from_tsi_peer(const tsi_peer* peer) {
182 if (peer == nullptr) {
183 gpr_log(GPR_ERROR,
184 "Invalid arguments to grpc_alts_auth_context_from_tsi_peer()");
185 return nullptr;
186 }
187 /* Validate certificate type. */
188 const tsi_peer_property* cert_type_prop =
189 tsi_peer_get_property_by_name(peer, TSI_CERTIFICATE_TYPE_PEER_PROPERTY);
190 if (cert_type_prop == nullptr ||
191 strncmp(cert_type_prop->value.data, TSI_ALTS_CERTIFICATE_TYPE,
192 cert_type_prop->value.length) != 0) {
193 gpr_log(GPR_ERROR, "Invalid or missing certificate type property.");
194 return nullptr;
195 }
196 /* Check if security level exists. */
197 const tsi_peer_property* security_level_prop =
198 tsi_peer_get_property_by_name(peer, TSI_SECURITY_LEVEL_PEER_PROPERTY);
199 if (security_level_prop == nullptr) {
200 gpr_log(GPR_ERROR, "Missing security level property.");
201 return nullptr;
202 }
203 /* Validate RPC protocol versions. */
204 const tsi_peer_property* rpc_versions_prop =
205 tsi_peer_get_property_by_name(peer, TSI_ALTS_RPC_VERSIONS);
206 if (rpc_versions_prop == nullptr) {
207 gpr_log(GPR_ERROR, "Missing rpc protocol versions property.");
208 return nullptr;
209 }
210 grpc_gcp_rpc_protocol_versions local_versions, peer_versions;
211 grpc_alts_set_rpc_protocol_versions(&local_versions);
212 grpc_slice slice = grpc_slice_from_copied_buffer(
213 rpc_versions_prop->value.data, rpc_versions_prop->value.length);
214 bool decode_result =
215 grpc_gcp_rpc_protocol_versions_decode(slice, &peer_versions);
216 grpc_slice_unref_internal(slice);
217 if (!decode_result) {
218 gpr_log(GPR_ERROR, "Invalid peer rpc protocol versions.");
219 return nullptr;
220 }
221 /* TODO: Pass highest common rpc protocol version to grpc caller. */
222 bool check_result = grpc_gcp_rpc_protocol_versions_check(
223 &local_versions, &peer_versions, nullptr);
224 if (!check_result) {
225 gpr_log(GPR_ERROR, "Mismatch of local and peer rpc protocol versions.");
226 return nullptr;
227 }
228 /* Validate ALTS Context. */
229 const tsi_peer_property* alts_context_prop =
230 tsi_peer_get_property_by_name(peer, TSI_ALTS_CONTEXT);
231 if (alts_context_prop == nullptr) {
232 gpr_log(GPR_ERROR, "Missing alts context property.");
233 return nullptr;
234 }
235 /* Create auth context. */
236 auto ctx = grpc_core::MakeRefCounted<grpc_auth_context>(nullptr);
237 grpc_auth_context_add_cstring_property(
238 ctx.get(), GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME,
239 GRPC_ALTS_TRANSPORT_SECURITY_TYPE);
240 size_t i = 0;
241 for (i = 0; i < peer->property_count; i++) {
242 const tsi_peer_property* tsi_prop = &peer->properties[i];
243 /* Add service account to auth context. */
244 if (strcmp(tsi_prop->name, TSI_ALTS_SERVICE_ACCOUNT_PEER_PROPERTY) == 0) {
245 grpc_auth_context_add_property(
246 ctx.get(), TSI_ALTS_SERVICE_ACCOUNT_PEER_PROPERTY,
247 tsi_prop->value.data, tsi_prop->value.length);
248 GPR_ASSERT(grpc_auth_context_set_peer_identity_property_name(
249 ctx.get(), TSI_ALTS_SERVICE_ACCOUNT_PEER_PROPERTY) == 1);
250 }
251 /* Add alts context to auth context. */
252 if (strcmp(tsi_prop->name, TSI_ALTS_CONTEXT) == 0) {
253 grpc_auth_context_add_property(ctx.get(), TSI_ALTS_CONTEXT,
254 tsi_prop->value.data,
255 tsi_prop->value.length);
256 }
257 /* Add security level to auth context. */
258 if (strcmp(tsi_prop->name, TSI_SECURITY_LEVEL_PEER_PROPERTY) == 0) {
259 grpc_auth_context_add_property(
260 ctx.get(), GRPC_TRANSPORT_SECURITY_LEVEL_PROPERTY_NAME,
261 tsi_prop->value.data, tsi_prop->value.length);
262 }
263 }
264 if (!grpc_auth_context_peer_is_authenticated(ctx.get())) {
265 gpr_log(GPR_ERROR, "Invalid unauthenticated peer.");
266 ctx.reset(DEBUG_LOCATION, "test");
267 return nullptr;
268 }
269 return ctx;
270 }
271
272 } // namespace internal
273 } // namespace grpc_core
274
275 grpc_core::RefCountedPtr<grpc_channel_security_connector>
grpc_alts_channel_security_connector_create(grpc_core::RefCountedPtr<grpc_channel_credentials> channel_creds,grpc_core::RefCountedPtr<grpc_call_credentials> request_metadata_creds,const char * target_name)276 grpc_alts_channel_security_connector_create(
277 grpc_core::RefCountedPtr<grpc_channel_credentials> channel_creds,
278 grpc_core::RefCountedPtr<grpc_call_credentials> request_metadata_creds,
279 const char* target_name) {
280 if (channel_creds == nullptr || target_name == nullptr) {
281 gpr_log(
282 GPR_ERROR,
283 "Invalid arguments to grpc_alts_channel_security_connector_create()");
284 return nullptr;
285 }
286 return grpc_core::MakeRefCounted<grpc_alts_channel_security_connector>(
287 std::move(channel_creds), std::move(request_metadata_creds), target_name);
288 }
289
290 grpc_core::RefCountedPtr<grpc_server_security_connector>
grpc_alts_server_security_connector_create(grpc_core::RefCountedPtr<grpc_server_credentials> server_creds)291 grpc_alts_server_security_connector_create(
292 grpc_core::RefCountedPtr<grpc_server_credentials> server_creds) {
293 if (server_creds == nullptr) {
294 gpr_log(
295 GPR_ERROR,
296 "Invalid arguments to grpc_alts_server_security_connector_create()");
297 return nullptr;
298 }
299 return grpc_core::MakeRefCounted<grpc_alts_server_security_connector>(
300 std::move(server_creds));
301 }
302