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