• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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