• 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_handle 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 
cancel_check_peer(grpc_closure *,grpc_error_handle error)106   void cancel_check_peer(grpc_closure* /*on_peer_checked*/,
107                          grpc_error_handle error) override {
108     GRPC_ERROR_UNREF(error);
109   }
110 
cmp(const grpc_security_connector * other_sc) const111   int cmp(const grpc_security_connector* other_sc) const override {
112     auto* other =
113         reinterpret_cast<const grpc_alts_channel_security_connector*>(other_sc);
114     int c = channel_security_connector_cmp(other);
115     if (c != 0) return c;
116     return strcmp(target_name_, other->target_name_);
117   }
118 
check_call_host(absl::string_view host,grpc_auth_context *,grpc_closure *,grpc_error_handle * error)119   bool check_call_host(absl::string_view host,
120                        grpc_auth_context* /*auth_context*/,
121                        grpc_closure* /*on_call_host_checked*/,
122                        grpc_error_handle* error) override {
123     if (host.empty() || host != target_name_) {
124       *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
125           "ALTS call host does not match target name");
126     }
127     return true;
128   }
129 
cancel_check_call_host(grpc_closure *,grpc_error_handle error)130   void cancel_check_call_host(grpc_closure* /*on_call_host_checked*/,
131                               grpc_error_handle error) override {
132     GRPC_ERROR_UNREF(error);
133   }
134 
135  private:
136   char* target_name_;
137 };
138 
139 class grpc_alts_server_security_connector final
140     : public grpc_server_security_connector {
141  public:
grpc_alts_server_security_connector(grpc_core::RefCountedPtr<grpc_server_credentials> server_creds)142   explicit grpc_alts_server_security_connector(
143       grpc_core::RefCountedPtr<grpc_server_credentials> server_creds)
144       : grpc_server_security_connector(GRPC_ALTS_URL_SCHEME,
145                                        std::move(server_creds)) {}
146 
147   ~grpc_alts_server_security_connector() override = default;
148 
add_handshakers(const grpc_channel_args * args,grpc_pollset_set * interested_parties,grpc_core::HandshakeManager * handshake_manager)149   void add_handshakers(
150       const grpc_channel_args* args, grpc_pollset_set* interested_parties,
151       grpc_core::HandshakeManager* handshake_manager) override {
152     tsi_handshaker* handshaker = nullptr;
153     const grpc_alts_server_credentials* creds =
154         static_cast<const grpc_alts_server_credentials*>(server_creds());
155     size_t user_specified_max_frame_size = 0;
156     const grpc_arg* arg =
157         grpc_channel_args_find(args, GRPC_ARG_TSI_MAX_FRAME_SIZE);
158     if (arg != nullptr && arg->type == GRPC_ARG_INTEGER) {
159       user_specified_max_frame_size = grpc_channel_arg_get_integer(
160           arg, {0, 0, std::numeric_limits<int>::max()});
161     }
162     GPR_ASSERT(alts_tsi_handshaker_create(
163                    creds->options(), nullptr, creds->handshaker_service_url(),
164                    false, interested_parties, &handshaker,
165                    user_specified_max_frame_size) == TSI_OK);
166     handshake_manager->Add(
167         grpc_core::SecurityHandshakerCreate(handshaker, this, args));
168   }
169 
check_peer(tsi_peer peer,grpc_endpoint *,grpc_core::RefCountedPtr<grpc_auth_context> * auth_context,grpc_closure * on_peer_checked)170   void check_peer(tsi_peer peer, grpc_endpoint* /*ep*/,
171                   grpc_core::RefCountedPtr<grpc_auth_context>* auth_context,
172                   grpc_closure* on_peer_checked) override {
173     alts_check_peer(peer, auth_context, on_peer_checked);
174   }
175 
cancel_check_peer(grpc_closure *,grpc_error_handle error)176   void cancel_check_peer(grpc_closure* /*on_peer_checked*/,
177                          grpc_error_handle error) override {
178     GRPC_ERROR_UNREF(error);
179   }
180 
cmp(const grpc_security_connector * other) const181   int cmp(const grpc_security_connector* other) const override {
182     return server_security_connector_cmp(
183         static_cast<const grpc_server_security_connector*>(other));
184   }
185 };
186 }  // namespace
187 
188 namespace grpc_core {
189 namespace internal {
190 grpc_core::RefCountedPtr<grpc_auth_context>
grpc_alts_auth_context_from_tsi_peer(const tsi_peer * peer)191 grpc_alts_auth_context_from_tsi_peer(const tsi_peer* peer) {
192   if (peer == nullptr) {
193     gpr_log(GPR_ERROR,
194             "Invalid arguments to grpc_alts_auth_context_from_tsi_peer()");
195     return nullptr;
196   }
197   /* Validate certificate type. */
198   const tsi_peer_property* cert_type_prop =
199       tsi_peer_get_property_by_name(peer, TSI_CERTIFICATE_TYPE_PEER_PROPERTY);
200   if (cert_type_prop == nullptr ||
201       strncmp(cert_type_prop->value.data, TSI_ALTS_CERTIFICATE_TYPE,
202               cert_type_prop->value.length) != 0) {
203     gpr_log(GPR_ERROR, "Invalid or missing certificate type property.");
204     return nullptr;
205   }
206   /* Check if security level exists. */
207   const tsi_peer_property* security_level_prop =
208       tsi_peer_get_property_by_name(peer, TSI_SECURITY_LEVEL_PEER_PROPERTY);
209   if (security_level_prop == nullptr) {
210     gpr_log(GPR_ERROR, "Missing security level property.");
211     return nullptr;
212   }
213   /* Validate RPC protocol versions. */
214   const tsi_peer_property* rpc_versions_prop =
215       tsi_peer_get_property_by_name(peer, TSI_ALTS_RPC_VERSIONS);
216   if (rpc_versions_prop == nullptr) {
217     gpr_log(GPR_ERROR, "Missing rpc protocol versions property.");
218     return nullptr;
219   }
220   grpc_gcp_rpc_protocol_versions local_versions, peer_versions;
221   grpc_alts_set_rpc_protocol_versions(&local_versions);
222   grpc_slice slice = grpc_slice_from_copied_buffer(
223       rpc_versions_prop->value.data, rpc_versions_prop->value.length);
224   bool decode_result =
225       grpc_gcp_rpc_protocol_versions_decode(slice, &peer_versions);
226   grpc_slice_unref_internal(slice);
227   if (!decode_result) {
228     gpr_log(GPR_ERROR, "Invalid peer rpc protocol versions.");
229     return nullptr;
230   }
231   /* TODO: Pass highest common rpc protocol version to grpc caller. */
232   bool check_result = grpc_gcp_rpc_protocol_versions_check(
233       &local_versions, &peer_versions, nullptr);
234   if (!check_result) {
235     gpr_log(GPR_ERROR, "Mismatch of local and peer rpc protocol versions.");
236     return nullptr;
237   }
238   /* Validate ALTS Context. */
239   const tsi_peer_property* alts_context_prop =
240       tsi_peer_get_property_by_name(peer, TSI_ALTS_CONTEXT);
241   if (alts_context_prop == nullptr) {
242     gpr_log(GPR_ERROR, "Missing alts context property.");
243     return nullptr;
244   }
245   /* Create auth context. */
246   auto ctx = grpc_core::MakeRefCounted<grpc_auth_context>(nullptr);
247   grpc_auth_context_add_cstring_property(
248       ctx.get(), GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME,
249       GRPC_ALTS_TRANSPORT_SECURITY_TYPE);
250   size_t i = 0;
251   for (i = 0; i < peer->property_count; i++) {
252     const tsi_peer_property* tsi_prop = &peer->properties[i];
253     /* Add service account to auth context. */
254     if (strcmp(tsi_prop->name, TSI_ALTS_SERVICE_ACCOUNT_PEER_PROPERTY) == 0) {
255       grpc_auth_context_add_property(
256           ctx.get(), TSI_ALTS_SERVICE_ACCOUNT_PEER_PROPERTY,
257           tsi_prop->value.data, tsi_prop->value.length);
258       GPR_ASSERT(grpc_auth_context_set_peer_identity_property_name(
259                      ctx.get(), TSI_ALTS_SERVICE_ACCOUNT_PEER_PROPERTY) == 1);
260     }
261     /* Add alts context to auth context. */
262     if (strcmp(tsi_prop->name, TSI_ALTS_CONTEXT) == 0) {
263       grpc_auth_context_add_property(ctx.get(), TSI_ALTS_CONTEXT,
264                                      tsi_prop->value.data,
265                                      tsi_prop->value.length);
266     }
267     /* Add security level to auth context. */
268     if (strcmp(tsi_prop->name, TSI_SECURITY_LEVEL_PEER_PROPERTY) == 0) {
269       grpc_auth_context_add_property(
270           ctx.get(), GRPC_TRANSPORT_SECURITY_LEVEL_PROPERTY_NAME,
271           tsi_prop->value.data, tsi_prop->value.length);
272     }
273   }
274   if (!grpc_auth_context_peer_is_authenticated(ctx.get())) {
275     gpr_log(GPR_ERROR, "Invalid unauthenticated peer.");
276     ctx.reset(DEBUG_LOCATION, "test");
277     return nullptr;
278   }
279   return ctx;
280 }
281 
282 }  // namespace internal
283 }  // namespace grpc_core
284 
285 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)286 grpc_alts_channel_security_connector_create(
287     grpc_core::RefCountedPtr<grpc_channel_credentials> channel_creds,
288     grpc_core::RefCountedPtr<grpc_call_credentials> request_metadata_creds,
289     const char* target_name) {
290   if (channel_creds == nullptr || target_name == nullptr) {
291     gpr_log(
292         GPR_ERROR,
293         "Invalid arguments to grpc_alts_channel_security_connector_create()");
294     return nullptr;
295   }
296   return grpc_core::MakeRefCounted<grpc_alts_channel_security_connector>(
297       std::move(channel_creds), std::move(request_metadata_creds), target_name);
298 }
299 
300 grpc_core::RefCountedPtr<grpc_server_security_connector>
grpc_alts_server_security_connector_create(grpc_core::RefCountedPtr<grpc_server_credentials> server_creds)301 grpc_alts_server_security_connector_create(
302     grpc_core::RefCountedPtr<grpc_server_credentials> server_creds) {
303   if (server_creds == nullptr) {
304     gpr_log(
305         GPR_ERROR,
306         "Invalid arguments to grpc_alts_server_security_connector_create()");
307     return nullptr;
308   }
309   return grpc_core::MakeRefCounted<grpc_alts_server_security_connector>(
310       std::move(server_creds));
311 }
312