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 <string.h>
24 
25 #include <algorithm>
26 #include <utility>
27 
28 #include "absl/status/status.h"
29 #include "absl/strings/string_view.h"
30 #include "absl/types/optional.h"
31 
32 #include <grpc/grpc.h>
33 #include <grpc/grpc_security_constants.h>
34 #include <grpc/slice.h>
35 #include <grpc/support/alloc.h>
36 #include <grpc/support/log.h>
37 #include <grpc/support/string_util.h>
38 
39 #include "src/core/lib/channel/channel_args.h"
40 #include "src/core/lib/gprpp/debug_location.h"
41 #include "src/core/lib/gprpp/ref_counted_ptr.h"
42 #include "src/core/lib/iomgr/closure.h"
43 #include "src/core/lib/iomgr/endpoint.h"
44 #include "src/core/lib/iomgr/error.h"
45 #include "src/core/lib/iomgr/exec_ctx.h"
46 #include "src/core/lib/iomgr/iomgr_fwd.h"
47 #include "src/core/lib/promise/arena_promise.h"
48 #include "src/core/lib/promise/promise.h"
49 #include "src/core/lib/security/context/security_context.h"
50 #include "src/core/lib/security/credentials/alts/alts_credentials.h"
51 #include "src/core/lib/security/credentials/credentials.h"
52 #include "src/core/lib/security/transport/security_handshaker.h"
53 #include "src/core/lib/slice/slice.h"
54 #include "src/core/lib/transport/handshaker.h"
55 #include "src/core/lib/transport/transport.h"
56 #include "src/core/tsi/alts/handshaker/alts_tsi_handshaker.h"
57 #include "src/core/tsi/transport_security.h"
58 
grpc_alts_set_rpc_protocol_versions(grpc_gcp_rpc_protocol_versions * rpc_versions)59 void grpc_alts_set_rpc_protocol_versions(
60     grpc_gcp_rpc_protocol_versions* rpc_versions) {
61   grpc_gcp_rpc_protocol_versions_set_max(rpc_versions,
62                                          GRPC_PROTOCOL_VERSION_MAX_MAJOR,
63                                          GRPC_PROTOCOL_VERSION_MAX_MINOR);
64   grpc_gcp_rpc_protocol_versions_set_min(rpc_versions,
65                                          GRPC_PROTOCOL_VERSION_MIN_MAJOR,
66                                          GRPC_PROTOCOL_VERSION_MIN_MINOR);
67 }
68 
69 namespace {
70 
alts_check_peer(tsi_peer peer,grpc_core::RefCountedPtr<grpc_auth_context> * auth_context,grpc_closure * on_peer_checked)71 void alts_check_peer(tsi_peer peer,
72                      grpc_core::RefCountedPtr<grpc_auth_context>* auth_context,
73                      grpc_closure* on_peer_checked) {
74   *auth_context =
75       grpc_core::internal::grpc_alts_auth_context_from_tsi_peer(&peer);
76   tsi_peer_destruct(&peer);
77   grpc_error_handle error =
78       *auth_context != nullptr
79           ? absl::OkStatus()
80           : GRPC_ERROR_CREATE("Could not get ALTS auth context from TSI peer");
81   grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_peer_checked, error);
82 }
83 
84 class grpc_alts_channel_security_connector final
85     : public grpc_channel_security_connector {
86  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)87   grpc_alts_channel_security_connector(
88       grpc_core::RefCountedPtr<grpc_channel_credentials> channel_creds,
89       grpc_core::RefCountedPtr<grpc_call_credentials> request_metadata_creds,
90       const char* target_name)
91       : grpc_channel_security_connector(GRPC_SSL_URL_SCHEME,
92                                         std::move(channel_creds),
93                                         std::move(request_metadata_creds)),
94         target_name_(gpr_strdup(target_name)) {}
95 
~grpc_alts_channel_security_connector()96   ~grpc_alts_channel_security_connector() override { gpr_free(target_name_); }
97 
add_handshakers(const grpc_core::ChannelArgs & args,grpc_pollset_set * interested_parties,grpc_core::HandshakeManager * handshake_manager)98   void add_handshakers(
99       const grpc_core::ChannelArgs& args, grpc_pollset_set* interested_parties,
100       grpc_core::HandshakeManager* handshake_manager) override {
101     tsi_handshaker* handshaker = nullptr;
102     const grpc_alts_credentials* creds =
103         static_cast<const grpc_alts_credentials*>(channel_creds());
104     const size_t user_specified_max_frame_size =
105         std::max(0, args.GetInt(GRPC_ARG_TSI_MAX_FRAME_SIZE).value_or(0));
106     GPR_ASSERT(alts_tsi_handshaker_create(
107                    creds->options(), target_name_,
108                    creds->handshaker_service_url(), true, interested_parties,
109                    &handshaker, user_specified_max_frame_size) == TSI_OK);
110     handshake_manager->Add(
111         grpc_core::SecurityHandshakerCreate(handshaker, this, args));
112   }
113 
check_peer(tsi_peer peer,grpc_endpoint *,const grpc_core::ChannelArgs &,grpc_core::RefCountedPtr<grpc_auth_context> * auth_context,grpc_closure * on_peer_checked)114   void check_peer(tsi_peer peer, grpc_endpoint* /*ep*/,
115                   const grpc_core::ChannelArgs& /*args*/,
116                   grpc_core::RefCountedPtr<grpc_auth_context>* auth_context,
117                   grpc_closure* on_peer_checked) override {
118     alts_check_peer(peer, auth_context, on_peer_checked);
119   }
120 
cancel_check_peer(grpc_closure *,grpc_error_handle)121   void cancel_check_peer(grpc_closure* /*on_peer_checked*/,
122                          grpc_error_handle /*error*/) override {}
123 
cmp(const grpc_security_connector * other_sc) const124   int cmp(const grpc_security_connector* other_sc) const override {
125     auto* other =
126         reinterpret_cast<const grpc_alts_channel_security_connector*>(other_sc);
127     int c = channel_security_connector_cmp(other);
128     if (c != 0) return c;
129     return strcmp(target_name_, other->target_name_);
130   }
131 
CheckCallHost(absl::string_view,grpc_auth_context *)132   grpc_core::ArenaPromise<absl::Status> CheckCallHost(
133       absl::string_view, grpc_auth_context*) override {
134     return grpc_core::ImmediateOkStatus();
135   }
136 
137  private:
138   char* target_name_;
139 };
140 
141 class grpc_alts_server_security_connector final
142     : public grpc_server_security_connector {
143  public:
grpc_alts_server_security_connector(grpc_core::RefCountedPtr<grpc_server_credentials> server_creds)144   explicit grpc_alts_server_security_connector(
145       grpc_core::RefCountedPtr<grpc_server_credentials> server_creds)
146       : grpc_server_security_connector(GRPC_SSL_URL_SCHEME,
147                                        std::move(server_creds)) {}
148 
149   ~grpc_alts_server_security_connector() override = default;
150 
add_handshakers(const grpc_core::ChannelArgs & args,grpc_pollset_set * interested_parties,grpc_core::HandshakeManager * handshake_manager)151   void add_handshakers(
152       const grpc_core::ChannelArgs& args, grpc_pollset_set* interested_parties,
153       grpc_core::HandshakeManager* handshake_manager) override {
154     tsi_handshaker* handshaker = nullptr;
155     const grpc_alts_server_credentials* creds =
156         static_cast<const grpc_alts_server_credentials*>(server_creds());
157     size_t user_specified_max_frame_size =
158         std::max(0, args.GetInt(GRPC_ARG_TSI_MAX_FRAME_SIZE).value_or(0));
159     GPR_ASSERT(alts_tsi_handshaker_create(
160                    creds->options(), nullptr, creds->handshaker_service_url(),
161                    false, interested_parties, &handshaker,
162                    user_specified_max_frame_size) == TSI_OK);
163     handshake_manager->Add(
164         grpc_core::SecurityHandshakerCreate(handshaker, this, args));
165   }
166 
check_peer(tsi_peer peer,grpc_endpoint *,const grpc_core::ChannelArgs &,grpc_core::RefCountedPtr<grpc_auth_context> * auth_context,grpc_closure * on_peer_checked)167   void check_peer(tsi_peer peer, grpc_endpoint* /*ep*/,
168                   const grpc_core::ChannelArgs& /*args*/,
169                   grpc_core::RefCountedPtr<grpc_auth_context>* auth_context,
170                   grpc_closure* on_peer_checked) override {
171     alts_check_peer(peer, auth_context, on_peer_checked);
172   }
173 
cancel_check_peer(grpc_closure *,grpc_error_handle)174   void cancel_check_peer(grpc_closure* /*on_peer_checked*/,
175                          grpc_error_handle /*error*/) override {}
176 
cmp(const grpc_security_connector * other) const177   int cmp(const grpc_security_connector* other) const override {
178     return server_security_connector_cmp(
179         static_cast<const grpc_server_security_connector*>(other));
180   }
181 };
182 }  // namespace
183 
184 namespace grpc_core {
185 namespace internal {
grpc_alts_auth_context_from_tsi_peer(const tsi_peer * peer)186 RefCountedPtr<grpc_auth_context> grpc_alts_auth_context_from_tsi_peer(
187     const tsi_peer* peer) {
188   if (peer == nullptr) {
189     gpr_log(GPR_ERROR,
190             "Invalid arguments to grpc_alts_auth_context_from_tsi_peer()");
191     return nullptr;
192   }
193   // Validate certificate type.
194   const tsi_peer_property* cert_type_prop =
195       tsi_peer_get_property_by_name(peer, TSI_CERTIFICATE_TYPE_PEER_PROPERTY);
196   if (cert_type_prop == nullptr ||
197       strncmp(cert_type_prop->value.data, TSI_ALTS_CERTIFICATE_TYPE,
198               cert_type_prop->value.length) != 0) {
199     gpr_log(GPR_ERROR, "Invalid or missing certificate type property.");
200     return nullptr;
201   }
202   // Check if security level exists.
203   const tsi_peer_property* security_level_prop =
204       tsi_peer_get_property_by_name(peer, TSI_SECURITY_LEVEL_PEER_PROPERTY);
205   if (security_level_prop == nullptr) {
206     gpr_log(GPR_ERROR, "Missing security level property.");
207     return nullptr;
208   }
209   // Validate RPC protocol versions.
210   const tsi_peer_property* rpc_versions_prop =
211       tsi_peer_get_property_by_name(peer, TSI_ALTS_RPC_VERSIONS);
212   if (rpc_versions_prop == nullptr) {
213     gpr_log(GPR_ERROR, "Missing rpc protocol versions property.");
214     return nullptr;
215   }
216   grpc_gcp_rpc_protocol_versions local_versions, peer_versions;
217   grpc_alts_set_rpc_protocol_versions(&local_versions);
218   grpc_slice slice = grpc_slice_from_copied_buffer(
219       rpc_versions_prop->value.data, rpc_versions_prop->value.length);
220   bool decode_result =
221       grpc_gcp_rpc_protocol_versions_decode(slice, &peer_versions);
222   CSliceUnref(slice);
223   if (!decode_result) {
224     gpr_log(GPR_ERROR, "Invalid peer rpc protocol versions.");
225     return nullptr;
226   }
227   // TODO(unknown): Pass highest common rpc protocol version to grpc caller.
228   bool check_result = grpc_gcp_rpc_protocol_versions_check(
229       &local_versions, &peer_versions, nullptr);
230   if (!check_result) {
231     gpr_log(GPR_ERROR, "Mismatch of local and peer rpc protocol versions.");
232     return nullptr;
233   }
234   // Validate ALTS Context.
235   const tsi_peer_property* alts_context_prop =
236       tsi_peer_get_property_by_name(peer, TSI_ALTS_CONTEXT);
237   if (alts_context_prop == nullptr) {
238     gpr_log(GPR_ERROR, "Missing alts context property.");
239     return nullptr;
240   }
241   // Create auth context.
242   auto ctx = MakeRefCounted<grpc_auth_context>(nullptr);
243   grpc_auth_context_add_cstring_property(
244       ctx.get(), GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME,
245       GRPC_ALTS_TRANSPORT_SECURITY_TYPE);
246   size_t i = 0;
247   for (i = 0; i < peer->property_count; i++) {
248     const tsi_peer_property* tsi_prop = &peer->properties[i];
249     // Add service account to auth context.
250     if (strcmp(tsi_prop->name, TSI_ALTS_SERVICE_ACCOUNT_PEER_PROPERTY) == 0) {
251       grpc_auth_context_add_property(
252           ctx.get(), TSI_ALTS_SERVICE_ACCOUNT_PEER_PROPERTY,
253           tsi_prop->value.data, tsi_prop->value.length);
254       GPR_ASSERT(grpc_auth_context_set_peer_identity_property_name(
255                      ctx.get(), TSI_ALTS_SERVICE_ACCOUNT_PEER_PROPERTY) == 1);
256     }
257     // Add alts context to auth context.
258     if (strcmp(tsi_prop->name, TSI_ALTS_CONTEXT) == 0) {
259       grpc_auth_context_add_property(ctx.get(), TSI_ALTS_CONTEXT,
260                                      tsi_prop->value.data,
261                                      tsi_prop->value.length);
262     }
263     // Add security level to auth context.
264     if (strcmp(tsi_prop->name, TSI_SECURITY_LEVEL_PEER_PROPERTY) == 0) {
265       grpc_auth_context_add_property(
266           ctx.get(), GRPC_TRANSPORT_SECURITY_LEVEL_PROPERTY_NAME,
267           tsi_prop->value.data, tsi_prop->value.length);
268     }
269   }
270   if (!grpc_auth_context_peer_is_authenticated(ctx.get())) {
271     gpr_log(GPR_ERROR, "Invalid unauthenticated peer.");
272     ctx.reset(DEBUG_LOCATION, "test");
273     return nullptr;
274   }
275   return ctx;
276 }
277 
278 }  // namespace internal
279 }  // namespace grpc_core
280 
281 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)282 grpc_alts_channel_security_connector_create(
283     grpc_core::RefCountedPtr<grpc_channel_credentials> channel_creds,
284     grpc_core::RefCountedPtr<grpc_call_credentials> request_metadata_creds,
285     const char* target_name) {
286   if (channel_creds == nullptr || target_name == nullptr) {
287     gpr_log(
288         GPR_ERROR,
289         "Invalid arguments to grpc_alts_channel_security_connector_create()");
290     return nullptr;
291   }
292   return grpc_core::MakeRefCounted<grpc_alts_channel_security_connector>(
293       std::move(channel_creds), std::move(request_metadata_creds), target_name);
294 }
295 
296 grpc_core::RefCountedPtr<grpc_server_security_connector>
grpc_alts_server_security_connector_create(grpc_core::RefCountedPtr<grpc_server_credentials> server_creds)297 grpc_alts_server_security_connector_create(
298     grpc_core::RefCountedPtr<grpc_server_credentials> server_creds) {
299   if (server_creds == nullptr) {
300     gpr_log(
301         GPR_ERROR,
302         "Invalid arguments to grpc_alts_server_security_connector_create()");
303     return nullptr;
304   }
305   return grpc_core::MakeRefCounted<grpc_alts_server_security_connector>(
306       std::move(server_creds));
307 }
308