Home | History | Annotate | Download | only in security_connector
      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_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/security/credentials/alts/alts_credentials.h"
     32 #include "src/core/lib/security/transport/security_handshaker.h"
     33 #include "src/core/lib/slice/slice_internal.h"
     34 #include "src/core/lib/transport/transport.h"
     35 #include "src/core/tsi/alts/handshaker/alts_tsi_handshaker.h"
     36 
     37 typedef struct {
     38   grpc_channel_security_connector base;
     39   char* target_name;
     40 } grpc_alts_channel_security_connector;
     41 
     42 typedef struct {
     43   grpc_server_security_connector base;
     44 } grpc_alts_server_security_connector;
     45 
     46 static void alts_channel_destroy(grpc_security_connector* sc) {
     47   if (sc == nullptr) {
     48     return;
     49   }
     50   auto c = reinterpret_cast<grpc_alts_channel_security_connector*>(sc);
     51   grpc_call_credentials_unref(c->base.request_metadata_creds);
     52   grpc_channel_credentials_unref(c->base.channel_creds);
     53   gpr_free(c->target_name);
     54   gpr_free(sc);
     55 }
     56 
     57 static void alts_server_destroy(grpc_security_connector* sc) {
     58   if (sc == nullptr) {
     59     return;
     60   }
     61   auto c = reinterpret_cast<grpc_alts_server_security_connector*>(sc);
     62   grpc_server_credentials_unref(c->base.server_creds);
     63   gpr_free(sc);
     64 }
     65 
     66 static void alts_channel_add_handshakers(
     67     grpc_channel_security_connector* sc,
     68     grpc_handshake_manager* handshake_manager) {
     69   tsi_handshaker* handshaker = nullptr;
     70   auto c = reinterpret_cast<grpc_alts_channel_security_connector*>(sc);
     71   grpc_alts_credentials* creds =
     72       reinterpret_cast<grpc_alts_credentials*>(c->base.channel_creds);
     73   GPR_ASSERT(alts_tsi_handshaker_create(creds->options, c->target_name,
     74                                         creds->handshaker_service_url, true,
     75                                         &handshaker) == TSI_OK);
     76   grpc_handshake_manager_add(handshake_manager, grpc_security_handshaker_create(
     77                                                     handshaker, &sc->base));
     78 }
     79 
     80 static void alts_server_add_handshakers(
     81     grpc_server_security_connector* sc,
     82     grpc_handshake_manager* handshake_manager) {
     83   tsi_handshaker* handshaker = nullptr;
     84   auto c = reinterpret_cast<grpc_alts_server_security_connector*>(sc);
     85   grpc_alts_server_credentials* creds =
     86       reinterpret_cast<grpc_alts_server_credentials*>(c->base.server_creds);
     87   GPR_ASSERT(alts_tsi_handshaker_create(creds->options, nullptr,
     88                                         creds->handshaker_service_url, false,
     89                                         &handshaker) == TSI_OK);
     90   grpc_handshake_manager_add(handshake_manager, grpc_security_handshaker_create(
     91                                                     handshaker, &sc->base));
     92 }
     93 
     94 static void alts_set_rpc_protocol_versions(
     95     grpc_gcp_rpc_protocol_versions* rpc_versions) {
     96   grpc_gcp_rpc_protocol_versions_set_max(rpc_versions,
     97                                          GRPC_PROTOCOL_VERSION_MAX_MAJOR,
     98                                          GRPC_PROTOCOL_VERSION_MAX_MINOR);
     99   grpc_gcp_rpc_protocol_versions_set_min(rpc_versions,
    100                                          GRPC_PROTOCOL_VERSION_MIN_MAJOR,
    101                                          GRPC_PROTOCOL_VERSION_MIN_MINOR);
    102 }
    103 
    104 namespace grpc_core {
    105 namespace internal {
    106 
    107 grpc_security_status grpc_alts_auth_context_from_tsi_peer(
    108     const tsi_peer* peer, grpc_auth_context** ctx) {
    109   if (peer == nullptr || ctx == nullptr) {
    110     gpr_log(GPR_ERROR,
    111             "Invalid arguments to grpc_alts_auth_context_from_tsi_peer()");
    112     return GRPC_SECURITY_ERROR;
    113   }
    114   *ctx = nullptr;
    115   /* Validate certificate type. */
    116   const tsi_peer_property* cert_type_prop =
    117       tsi_peer_get_property_by_name(peer, TSI_CERTIFICATE_TYPE_PEER_PROPERTY);
    118   if (cert_type_prop == nullptr ||
    119       strncmp(cert_type_prop->value.data, TSI_ALTS_CERTIFICATE_TYPE,
    120               cert_type_prop->value.length) != 0) {
    121     gpr_log(GPR_ERROR, "Invalid or missing certificate type property.");
    122     return GRPC_SECURITY_ERROR;
    123   }
    124   /* Validate RPC protocol versions. */
    125   const tsi_peer_property* rpc_versions_prop =
    126       tsi_peer_get_property_by_name(peer, TSI_ALTS_RPC_VERSIONS);
    127   if (rpc_versions_prop == nullptr) {
    128     gpr_log(GPR_ERROR, "Missing rpc protocol versions property.");
    129     return GRPC_SECURITY_ERROR;
    130   }
    131   grpc_gcp_rpc_protocol_versions local_versions, peer_versions;
    132   alts_set_rpc_protocol_versions(&local_versions);
    133   grpc_slice slice = grpc_slice_from_copied_buffer(
    134       rpc_versions_prop->value.data, rpc_versions_prop->value.length);
    135   bool decode_result =
    136       grpc_gcp_rpc_protocol_versions_decode(slice, &peer_versions);
    137   grpc_slice_unref_internal(slice);
    138   if (!decode_result) {
    139     gpr_log(GPR_ERROR, "Invalid peer rpc protocol versions.");
    140     return GRPC_SECURITY_ERROR;
    141   }
    142   /* TODO: Pass highest common rpc protocol version to grpc caller. */
    143   bool check_result = grpc_gcp_rpc_protocol_versions_check(
    144       &local_versions, &peer_versions, nullptr);
    145   if (!check_result) {
    146     gpr_log(GPR_ERROR, "Mismatch of local and peer rpc protocol versions.");
    147     return GRPC_SECURITY_ERROR;
    148   }
    149   /* Create auth context. */
    150   *ctx = grpc_auth_context_create(nullptr);
    151   grpc_auth_context_add_cstring_property(
    152       *ctx, GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME,
    153       GRPC_ALTS_TRANSPORT_SECURITY_TYPE);
    154   size_t i = 0;
    155   for (i = 0; i < peer->property_count; i++) {
    156     const tsi_peer_property* tsi_prop = &peer->properties[i];
    157     /* Add service account to auth context. */
    158     if (strcmp(tsi_prop->name, TSI_ALTS_SERVICE_ACCOUNT_PEER_PROPERTY) == 0) {
    159       grpc_auth_context_add_property(
    160           *ctx, TSI_ALTS_SERVICE_ACCOUNT_PEER_PROPERTY, tsi_prop->value.data,
    161           tsi_prop->value.length);
    162       GPR_ASSERT(grpc_auth_context_set_peer_identity_property_name(
    163                      *ctx, TSI_ALTS_SERVICE_ACCOUNT_PEER_PROPERTY) == 1);
    164     }
    165   }
    166   if (!grpc_auth_context_peer_is_authenticated(*ctx)) {
    167     gpr_log(GPR_ERROR, "Invalid unauthenticated peer.");
    168     GRPC_AUTH_CONTEXT_UNREF(*ctx, "test");
    169     *ctx = nullptr;
    170     return GRPC_SECURITY_ERROR;
    171   }
    172   return GRPC_SECURITY_OK;
    173 }
    174 
    175 }  // namespace internal
    176 }  // namespace grpc_core
    177 
    178 static void alts_check_peer(grpc_security_connector* sc, tsi_peer peer,
    179                             grpc_auth_context** auth_context,
    180                             grpc_closure* on_peer_checked) {
    181   grpc_security_status status;
    182   status = grpc_core::internal::grpc_alts_auth_context_from_tsi_peer(
    183       &peer, auth_context);
    184   tsi_peer_destruct(&peer);
    185   grpc_error* error =
    186       status == GRPC_SECURITY_OK
    187           ? GRPC_ERROR_NONE
    188           : GRPC_ERROR_CREATE_FROM_STATIC_STRING(
    189                 "Could not get ALTS auth context from TSI peer");
    190   GRPC_CLOSURE_SCHED(on_peer_checked, error);
    191 }
    192 
    193 static int alts_channel_cmp(grpc_security_connector* sc1,
    194                             grpc_security_connector* sc2) {
    195   grpc_alts_channel_security_connector* c1 =
    196       reinterpret_cast<grpc_alts_channel_security_connector*>(sc1);
    197   grpc_alts_channel_security_connector* c2 =
    198       reinterpret_cast<grpc_alts_channel_security_connector*>(sc2);
    199   int c = grpc_channel_security_connector_cmp(&c1->base, &c2->base);
    200   if (c != 0) return c;
    201   return strcmp(c1->target_name, c2->target_name);
    202 }
    203 
    204 static int alts_server_cmp(grpc_security_connector* sc1,
    205                            grpc_security_connector* sc2) {
    206   grpc_alts_server_security_connector* c1 =
    207       reinterpret_cast<grpc_alts_server_security_connector*>(sc1);
    208   grpc_alts_server_security_connector* c2 =
    209       reinterpret_cast<grpc_alts_server_security_connector*>(sc2);
    210   return grpc_server_security_connector_cmp(&c1->base, &c2->base);
    211 }
    212 
    213 static grpc_security_connector_vtable alts_channel_vtable = {
    214     alts_channel_destroy, alts_check_peer, alts_channel_cmp};
    215 
    216 static grpc_security_connector_vtable alts_server_vtable = {
    217     alts_server_destroy, alts_check_peer, alts_server_cmp};
    218 
    219 static bool alts_check_call_host(grpc_channel_security_connector* sc,
    220                                  const char* host,
    221                                  grpc_auth_context* auth_context,
    222                                  grpc_closure* on_call_host_checked,
    223                                  grpc_error** error) {
    224   grpc_alts_channel_security_connector* alts_sc =
    225       reinterpret_cast<grpc_alts_channel_security_connector*>(sc);
    226   if (host == nullptr || alts_sc == nullptr ||
    227       strcmp(host, alts_sc->target_name) != 0) {
    228     *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
    229         "ALTS call host does not match target name");
    230   }
    231   return true;
    232 }
    233 
    234 static void alts_cancel_check_call_host(grpc_channel_security_connector* sc,
    235                                         grpc_closure* on_call_host_checked,
    236                                         grpc_error* error) {
    237   GRPC_ERROR_UNREF(error);
    238 }
    239 
    240 grpc_security_status grpc_alts_channel_security_connector_create(
    241     grpc_channel_credentials* channel_creds,
    242     grpc_call_credentials* request_metadata_creds, const char* target_name,
    243     grpc_channel_security_connector** sc) {
    244   if (channel_creds == nullptr || sc == nullptr || target_name == nullptr) {
    245     gpr_log(
    246         GPR_ERROR,
    247         "Invalid arguments to grpc_alts_channel_security_connector_create()");
    248     return GRPC_SECURITY_ERROR;
    249   }
    250   auto c = static_cast<grpc_alts_channel_security_connector*>(
    251       gpr_zalloc(sizeof(grpc_alts_channel_security_connector)));
    252   gpr_ref_init(&c->base.base.refcount, 1);
    253   c->base.base.vtable = &alts_channel_vtable;
    254   c->base.add_handshakers = alts_channel_add_handshakers;
    255   c->base.channel_creds = grpc_channel_credentials_ref(channel_creds);
    256   c->base.request_metadata_creds =
    257       grpc_call_credentials_ref(request_metadata_creds);
    258   c->base.check_call_host = alts_check_call_host;
    259   c->base.cancel_check_call_host = alts_cancel_check_call_host;
    260   grpc_alts_credentials* creds =
    261       reinterpret_cast<grpc_alts_credentials*>(c->base.channel_creds);
    262   alts_set_rpc_protocol_versions(&creds->options->rpc_versions);
    263   c->target_name = gpr_strdup(target_name);
    264   *sc = &c->base;
    265   return GRPC_SECURITY_OK;
    266 }
    267 
    268 grpc_security_status grpc_alts_server_security_connector_create(
    269     grpc_server_credentials* server_creds,
    270     grpc_server_security_connector** sc) {
    271   if (server_creds == nullptr || sc == nullptr) {
    272     gpr_log(
    273         GPR_ERROR,
    274         "Invalid arguments to grpc_alts_server_security_connector_create()");
    275     return GRPC_SECURITY_ERROR;
    276   }
    277   auto c = static_cast<grpc_alts_server_security_connector*>(
    278       gpr_zalloc(sizeof(grpc_alts_server_security_connector)));
    279   gpr_ref_init(&c->base.base.refcount, 1);
    280   c->base.base.vtable = &alts_server_vtable;
    281   c->base.server_creds = grpc_server_credentials_ref(server_creds);
    282   c->base.add_handshakers = alts_server_add_handshakers;
    283   grpc_alts_server_credentials* creds =
    284       reinterpret_cast<grpc_alts_server_credentials*>(c->base.server_creds);
    285   alts_set_rpc_protocol_versions(&creds->options->rpc_versions);
    286   *sc = &c->base;
    287   return GRPC_SECURITY_OK;
    288 }
    289