1 /*
2  *
3  * Copyright 2015 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/http/httpcli.h"
22 
23 #include <string.h>
24 
25 #include <grpc/support/alloc.h>
26 #include <grpc/support/log.h>
27 #include <grpc/support/string_util.h>
28 
29 #include "src/core/lib/channel/channel_args.h"
30 #include "src/core/lib/channel/handshaker_registry.h"
31 #include "src/core/lib/gpr/string.h"
32 #include "src/core/lib/security/transport/security_handshaker.h"
33 #include "src/core/lib/slice/slice_internal.h"
34 #include "src/core/tsi/ssl_transport_security.h"
35 
36 typedef struct {
37   grpc_channel_security_connector base;
38   tsi_ssl_client_handshaker_factory* handshaker_factory;
39   char* secure_peer_name;
40 } grpc_httpcli_ssl_channel_security_connector;
41 
httpcli_ssl_destroy(grpc_security_connector * sc)42 static void httpcli_ssl_destroy(grpc_security_connector* sc) {
43   grpc_httpcli_ssl_channel_security_connector* c =
44       reinterpret_cast<grpc_httpcli_ssl_channel_security_connector*>(sc);
45   if (c->handshaker_factory != nullptr) {
46     tsi_ssl_client_handshaker_factory_unref(c->handshaker_factory);
47     c->handshaker_factory = nullptr;
48   }
49   if (c->secure_peer_name != nullptr) gpr_free(c->secure_peer_name);
50   gpr_free(sc);
51 }
52 
httpcli_ssl_add_handshakers(grpc_channel_security_connector * sc,grpc_handshake_manager * handshake_mgr)53 static void httpcli_ssl_add_handshakers(grpc_channel_security_connector* sc,
54                                         grpc_handshake_manager* handshake_mgr) {
55   grpc_httpcli_ssl_channel_security_connector* c =
56       reinterpret_cast<grpc_httpcli_ssl_channel_security_connector*>(sc);
57   tsi_handshaker* handshaker = nullptr;
58   if (c->handshaker_factory != nullptr) {
59     tsi_result result = tsi_ssl_client_handshaker_factory_create_handshaker(
60         c->handshaker_factory, c->secure_peer_name, &handshaker);
61     if (result != TSI_OK) {
62       gpr_log(GPR_ERROR, "Handshaker creation failed with error %s.",
63               tsi_result_to_string(result));
64     }
65   }
66   grpc_handshake_manager_add(
67       handshake_mgr, grpc_security_handshaker_create(handshaker, &sc->base));
68 }
69 
httpcli_ssl_check_peer(grpc_security_connector * sc,tsi_peer peer,grpc_auth_context ** auth_context,grpc_closure * on_peer_checked)70 static void httpcli_ssl_check_peer(grpc_security_connector* sc, tsi_peer peer,
71                                    grpc_auth_context** auth_context,
72                                    grpc_closure* on_peer_checked) {
73   grpc_httpcli_ssl_channel_security_connector* c =
74       reinterpret_cast<grpc_httpcli_ssl_channel_security_connector*>(sc);
75   grpc_error* error = GRPC_ERROR_NONE;
76 
77   /* Check the peer name. */
78   if (c->secure_peer_name != nullptr &&
79       !tsi_ssl_peer_matches_name(&peer, c->secure_peer_name)) {
80     char* msg;
81     gpr_asprintf(&msg, "Peer name %s is not in peer certificate",
82                  c->secure_peer_name);
83     error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg);
84     gpr_free(msg);
85   }
86   GRPC_CLOSURE_SCHED(on_peer_checked, error);
87   tsi_peer_destruct(&peer);
88 }
89 
httpcli_ssl_cmp(grpc_security_connector * sc1,grpc_security_connector * sc2)90 static int httpcli_ssl_cmp(grpc_security_connector* sc1,
91                            grpc_security_connector* sc2) {
92   grpc_httpcli_ssl_channel_security_connector* c1 =
93       reinterpret_cast<grpc_httpcli_ssl_channel_security_connector*>(sc1);
94   grpc_httpcli_ssl_channel_security_connector* c2 =
95       reinterpret_cast<grpc_httpcli_ssl_channel_security_connector*>(sc2);
96   return strcmp(c1->secure_peer_name, c2->secure_peer_name);
97 }
98 
99 static grpc_security_connector_vtable httpcli_ssl_vtable = {
100     httpcli_ssl_destroy, httpcli_ssl_check_peer, httpcli_ssl_cmp};
101 
httpcli_ssl_channel_security_connector_create(const char * pem_root_certs,const tsi_ssl_root_certs_store * root_store,const char * secure_peer_name,grpc_channel_security_connector ** sc)102 static grpc_security_status httpcli_ssl_channel_security_connector_create(
103     const char* pem_root_certs, const tsi_ssl_root_certs_store* root_store,
104     const char* secure_peer_name, grpc_channel_security_connector** sc) {
105   tsi_result result = TSI_OK;
106   grpc_httpcli_ssl_channel_security_connector* c;
107 
108   if (secure_peer_name != nullptr && pem_root_certs == nullptr) {
109     gpr_log(GPR_ERROR,
110             "Cannot assert a secure peer name without a trust root.");
111     return GRPC_SECURITY_ERROR;
112   }
113 
114   c = static_cast<grpc_httpcli_ssl_channel_security_connector*>(
115       gpr_zalloc(sizeof(grpc_httpcli_ssl_channel_security_connector)));
116 
117   gpr_ref_init(&c->base.base.refcount, 1);
118   c->base.base.vtable = &httpcli_ssl_vtable;
119   if (secure_peer_name != nullptr) {
120     c->secure_peer_name = gpr_strdup(secure_peer_name);
121   }
122   tsi_ssl_client_handshaker_options options;
123   memset(&options, 0, sizeof(options));
124   options.pem_root_certs = pem_root_certs;
125   options.root_store = root_store;
126   result = tsi_create_ssl_client_handshaker_factory_with_options(
127       &options, &c->handshaker_factory);
128   if (result != TSI_OK) {
129     gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.",
130             tsi_result_to_string(result));
131     httpcli_ssl_destroy(&c->base.base);
132     *sc = nullptr;
133     return GRPC_SECURITY_ERROR;
134   }
135   // We don't actually need a channel credentials object in this case,
136   // but we set it to a non-nullptr address so that we don't trigger
137   // assertions in grpc_channel_security_connector_cmp().
138   c->base.channel_creds = (grpc_channel_credentials*)1;
139   c->base.add_handshakers = httpcli_ssl_add_handshakers;
140   *sc = &c->base;
141   return GRPC_SECURITY_OK;
142 }
143 
144 /* handshaker */
145 
146 typedef struct {
147   void (*func)(void* arg, grpc_endpoint* endpoint);
148   void* arg;
149   grpc_handshake_manager* handshake_mgr;
150 } on_done_closure;
151 
on_handshake_done(void * arg,grpc_error * error)152 static void on_handshake_done(void* arg, grpc_error* error) {
153   grpc_handshaker_args* args = static_cast<grpc_handshaker_args*>(arg);
154   on_done_closure* c = static_cast<on_done_closure*>(args->user_data);
155   if (error != GRPC_ERROR_NONE) {
156     const char* msg = grpc_error_string(error);
157     gpr_log(GPR_ERROR, "Secure transport setup failed: %s", msg);
158 
159     c->func(c->arg, nullptr);
160   } else {
161     grpc_channel_args_destroy(args->args);
162     grpc_slice_buffer_destroy_internal(args->read_buffer);
163     gpr_free(args->read_buffer);
164     c->func(c->arg, args->endpoint);
165   }
166   grpc_handshake_manager_destroy(c->handshake_mgr);
167   gpr_free(c);
168 }
169 
ssl_handshake(void * arg,grpc_endpoint * tcp,const char * host,grpc_millis deadline,void (* on_done)(void * arg,grpc_endpoint * endpoint))170 static void ssl_handshake(void* arg, grpc_endpoint* tcp, const char* host,
171                           grpc_millis deadline,
172                           void (*on_done)(void* arg, grpc_endpoint* endpoint)) {
173   on_done_closure* c = static_cast<on_done_closure*>(gpr_malloc(sizeof(*c)));
174   const char* pem_root_certs =
175       grpc_core::DefaultSslRootStore::GetPemRootCerts();
176   const tsi_ssl_root_certs_store* root_store =
177       grpc_core::DefaultSslRootStore::GetRootStore();
178   if (root_store == nullptr) {
179     gpr_log(GPR_ERROR, "Could not get default pem root certs.");
180     on_done(arg, nullptr);
181     gpr_free(c);
182     return;
183   }
184   c->func = on_done;
185   c->arg = arg;
186   grpc_channel_security_connector* sc = nullptr;
187   GPR_ASSERT(httpcli_ssl_channel_security_connector_create(
188                  pem_root_certs, root_store, host, &sc) == GRPC_SECURITY_OK);
189   grpc_arg channel_arg = grpc_security_connector_to_arg(&sc->base);
190   grpc_channel_args args = {1, &channel_arg};
191   c->handshake_mgr = grpc_handshake_manager_create();
192   grpc_handshakers_add(HANDSHAKER_CLIENT, &args, c->handshake_mgr);
193   grpc_handshake_manager_do_handshake(
194       c->handshake_mgr, nullptr /* interested_parties */, tcp,
195       nullptr /* channel_args */, deadline, nullptr /* acceptor */,
196       on_handshake_done, c /* user_data */);
197   GRPC_SECURITY_CONNECTOR_UNREF(&sc->base, "httpcli");
198 }
199 
200 const grpc_httpcli_handshaker grpc_httpcli_ssl = {"https", ssl_handshake};
201