| 1 | // |
| 2 | // Copyright 2021 gRPC authors. |
| 3 | // |
| 4 | // Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | // you may not use this file except in compliance with the License. |
| 6 | // You may obtain a copy of the License at |
| 7 | // |
| 8 | // http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | // |
| 10 | // Unless required by applicable law or agreed to in writing, software |
| 11 | // distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | // See the License for the specific language governing permissions and |
| 14 | // limitations under the License. |
| 15 | // |
| 16 | |
| 17 | #ifndef GRPCPP_SECURITY_TLS_CERTIFICATE_VERIFIER_H |
| 18 | #define GRPCPP_SECURITY_TLS_CERTIFICATE_VERIFIER_H |
| 19 | |
| 20 | #include <functional> |
| 21 | #include <map> |
| 22 | #include <memory> |
| 23 | #include <utility> |
| 24 | #include <vector> |
| 25 | |
| 26 | #include <grpc/grpc_security_constants.h> |
| 27 | #include <grpc/status.h> |
| 28 | #include <grpc/support/log.h> |
| 29 | #include <grpcpp/impl/codegen/grpc_library.h> |
| 30 | #include <grpcpp/impl/codegen/sync.h> |
| 31 | #include <grpcpp/impl/grpc_library.h> |
| 32 | #include <grpcpp/support/config.h> |
| 33 | #include <grpcpp/support/string_ref.h> |
| 34 | |
| 35 | // TODO(yihuazhang): remove the forward declaration here and include |
| 36 | // <grpc/grpc_security.h> directly once the insecure builds are cleaned up. |
| 37 | typedef struct grpc_tls_custom_verification_check_request |
| 38 | grpc_tls_custom_verification_check_request; |
| 39 | typedef struct grpc_tls_certificate_verifier grpc_tls_certificate_verifier; |
| 40 | typedef struct grpc_tls_certificate_verifier_external |
| 41 | grpc_tls_certificate_verifier_external; |
| 42 | typedef void (*grpc_tls_on_custom_verification_check_done_cb)( |
| 43 | grpc_tls_custom_verification_check_request* request, void* callback_arg, |
| 44 | grpc_status_code status, const char* error_details); |
| 45 | extern "C" grpc_tls_certificate_verifier* |
| 46 | grpc_tls_certificate_verifier_external_create( |
| 47 | grpc_tls_certificate_verifier_external* external_verifier); |
| 48 | |
| 49 | namespace grpc { |
| 50 | namespace experimental { |
| 51 | |
| 52 | // Contains the verification-related information associated with a connection |
| 53 | // request. Users should not directly create or destroy this request object, but |
| 54 | // shall interact with it through CertificateVerifier's Verify() and Cancel(). |
| 55 | class TlsCustomVerificationCheckRequest { |
| 56 | public: |
| 57 | explicit TlsCustomVerificationCheckRequest( |
| 58 | grpc_tls_custom_verification_check_request* request); |
| 59 | ~TlsCustomVerificationCheckRequest() {} |
| 60 | |
| 61 | grpc::string_ref target_name() const; |
| 62 | grpc::string_ref peer_cert() const; |
| 63 | grpc::string_ref peer_cert_full_chain() const; |
| 64 | grpc::string_ref common_name() const; |
| 65 | std::vector<grpc::string_ref> uri_names() const; |
| 66 | std::vector<grpc::string_ref> dns_names() const; |
| 67 | std::vector<grpc::string_ref> email_names() const; |
| 68 | std::vector<grpc::string_ref> ip_names() const; |
| 69 | |
| 70 | grpc_tls_custom_verification_check_request* c_request() { return c_request_; } |
| 71 | |
| 72 | private: |
| 73 | grpc_tls_custom_verification_check_request* c_request_ = nullptr; |
| 74 | }; |
| 75 | |
| 76 | // The base class of all internal verifier implementations, and the ultimate |
| 77 | // class that all external verifiers will eventually be transformed into. |
| 78 | // To implement a custom verifier, do not extend this class; instead, |
| 79 | // implement a subclass of ExternalCertificateVerifier. Note that custom |
| 80 | // verifier implementations can compose their functionality with existing |
| 81 | // implementations of this interface, such as HostnameVerifier, by delegating |
| 82 | // to an instance of that class. |
| 83 | class CertificateVerifier { |
| 84 | public: |
| 85 | explicit CertificateVerifier(grpc_tls_certificate_verifier* v); |
| 86 | |
| 87 | ~CertificateVerifier(); |
| 88 | |
| 89 | // Verifies a connection request, based on the logic specified in an internal |
| 90 | // verifier. The check on each internal verifier could be either synchronous |
| 91 | // or asynchronous, and we will need to use return value to know. |
| 92 | // |
| 93 | // request: the verification information associated with this request |
| 94 | // callback: This will only take effect if the verifier is asynchronous. |
| 95 | // The function that gRPC will invoke when the verifier has already |
| 96 | // completed its asynchronous check. Callers can use this function |
| 97 | // to perform any additional checks. The input parameter of the |
| 98 | // std::function indicates the status of the verifier check. |
| 99 | // sync_status: This will only be useful if the verifier is synchronous. |
| 100 | // The status of the verifier as it has already done it's |
| 101 | // synchronous check. |
| 102 | // return: return true if executed synchronously, otherwise return false |
| 103 | bool Verify(TlsCustomVerificationCheckRequest* request, |
| 104 | std::function<void(grpc::Status)> callback, |
| 105 | grpc::Status* sync_status); |
| 106 | |
| 107 | // Cancels a verification request previously started via Verify(). |
| 108 | // Used when the connection attempt times out or is cancelled while an async |
| 109 | // verification request is pending. |
| 110 | // |
| 111 | // request: the verification information associated with this request |
| 112 | void Cancel(TlsCustomVerificationCheckRequest* request); |
| 113 | |
| 114 | // Gets the core verifier used internally. |
| 115 | grpc_tls_certificate_verifier* c_verifier() { return verifier_; } |
| 116 | |
| 117 | private: |
| 118 | static void AsyncCheckDone( |
| 119 | grpc_tls_custom_verification_check_request* request, void* callback_arg, |
| 120 | grpc_status_code status, const char* error_details); |
| 121 | |
| 122 | grpc_tls_certificate_verifier* verifier_ = nullptr; |
| 123 | grpc::internal::Mutex mu_; |
| 124 | std::map<grpc_tls_custom_verification_check_request*, |
| 125 | std::function<void(grpc::Status)>> |
| 126 | request_map_ ABSL_GUARDED_BY(mu_); |
| 127 | }; |
| 128 | |
| 129 | // The base class of all external, user-specified verifiers. Users should |
| 130 | // inherit this class to implement a custom verifier. |
| 131 | // Note that while implementing the custom verifier that extends this class, it |
| 132 | // is possible to compose an existing ExternalCertificateVerifier or |
| 133 | // CertificateVerifier, inside the Verify() and Cancel() function of the new |
| 134 | // custom verifier. |
| 135 | class ExternalCertificateVerifier { |
| 136 | public: |
| 137 | // A factory method for creating a |CertificateVerifier| from this class. All |
| 138 | // the user-implemented verifiers should use this function to be converted to |
| 139 | // verifiers compatible with |TlsCredentialsOptions|. |
| 140 | // The resulting CertificateVerifier takes ownership of the newly instantiated |
| 141 | // Subclass. |
| 142 | template <typename Subclass, typename... Args> |
| 143 | static std::shared_ptr<CertificateVerifier> Create(Args&&... args) { |
| 144 | grpc::internal::GrpcLibraryInitializer g_gli_initializer; |
| 145 | g_gli_initializer.summon(); |
| 146 | auto* external_verifier = new Subclass(std::forward<Args>(args)...); |
| 147 | return std::make_shared<CertificateVerifier>( |
| 148 | grpc_tls_certificate_verifier_external_create( |
| 149 | external_verifier->base_)); |
| 150 | } |
| 151 | |
| 152 | // The verification logic that will be performed after the TLS handshake |
| 153 | // completes. Implementers can choose to do their checks synchronously or |
| 154 | // asynchronously. |
| 155 | // |
| 156 | // request: the verification information associated with this request |
| 157 | // callback: This should only be used if your check is done asynchronously. |
| 158 | // When the asynchronous work is done, invoke this callback function |
| 159 | // with the proper status, indicating the success or the failure of |
| 160 | // the check. The implementer MUST NOT invoke this |callback| in the |
| 161 | // same thread before Verify() returns, otherwise it can lead to |
| 162 | // deadlocks. |
| 163 | // sync_status: This should only be used if your check is done synchronously. |
| 164 | // Modifies this value to indicate the success or the failure of |
| 165 | // the check. |
| 166 | // return: return true if your check is done synchronously, otherwise return |
| 167 | // false |
| 168 | virtual bool Verify(TlsCustomVerificationCheckRequest* request, |
| 169 | std::function<void(grpc::Status)> callback, |
| 170 | grpc::Status* sync_status) = 0; |
| 171 | |
| 172 | // Cancels a verification request previously started via Verify(). |
| 173 | // Used when the connection attempt times out or is cancelled while an async |
| 174 | // verification request is pending. The implementation should abort whatever |
| 175 | // async operation it is waiting for and quickly invoke the callback that was |
| 176 | // passed to Verify() with a status indicating the cancellation. |
| 177 | // |
| 178 | // request: the verification information associated with this request |
| 179 | virtual void Cancel(TlsCustomVerificationCheckRequest* request) = 0; |
| 180 | |
| 181 | protected: |
| 182 | ExternalCertificateVerifier(); |
| 183 | |
| 184 | virtual ~ExternalCertificateVerifier(); |
| 185 | |
| 186 | private: |
| 187 | struct AsyncRequestState { |
| 188 | AsyncRequestState(grpc_tls_on_custom_verification_check_done_cb cb, |
| 189 | void* arg, |
| 190 | grpc_tls_custom_verification_check_request* request) |
| 191 | : callback(cb), callback_arg(arg), cpp_request(request) {} |
| 192 | |
| 193 | grpc_tls_on_custom_verification_check_done_cb callback; |
| 194 | void* callback_arg; |
| 195 | TlsCustomVerificationCheckRequest cpp_request; |
| 196 | }; |
| 197 | |
| 198 | static int VerifyInCoreExternalVerifier( |
| 199 | void* user_data, grpc_tls_custom_verification_check_request* request, |
| 200 | grpc_tls_on_custom_verification_check_done_cb callback, |
| 201 | void* callback_arg, grpc_status_code* sync_status, |
| 202 | char** sync_error_details); |
| 203 | |
| 204 | static void CancelInCoreExternalVerifier( |
| 205 | void* user_data, grpc_tls_custom_verification_check_request* request); |
| 206 | |
| 207 | static void DestructInCoreExternalVerifier(void* user_data); |
| 208 | |
| 209 | // TODO(yihuazhang): after the insecure build is removed, make this an object |
| 210 | // member instead of a pointer. |
| 211 | grpc_tls_certificate_verifier_external* base_ = nullptr; |
| 212 | grpc::internal::Mutex mu_; |
| 213 | std::map<grpc_tls_custom_verification_check_request*, AsyncRequestState> |
| 214 | request_map_ ABSL_GUARDED_BY(mu_); |
| 215 | }; |
| 216 | |
| 217 | // A CertificateVerifier that doesn't perform any additional checks other than |
| 218 | // certificate verification, if specified. |
| 219 | // Note: using this solely without any other authentication mechanisms on the |
| 220 | // peer identity will leave your applications to the MITM(Man-In-The-Middle) |
| 221 | // attacks. Users should avoid doing so in production environments. |
| 222 | class NoOpCertificateVerifier : public CertificateVerifier { |
| 223 | public: |
| 224 | NoOpCertificateVerifier(); |
| 225 | }; |
| 226 | |
| 227 | // A CertificateVerifier that will perform hostname verification, to see if the |
| 228 | // target name set from the client side matches the identity information |
| 229 | // specified on the server's certificate. |
| 230 | class HostNameCertificateVerifier : public CertificateVerifier { |
| 231 | public: |
| 232 | HostNameCertificateVerifier(); |
| 233 | }; |
| 234 | |
| 235 | } // namespace experimental |
| 236 | } // namespace grpc |
| 237 | |
| 238 | #endif // GRPCPP_SECURITY_TLS_CERTIFICATE_VERIFIER_H |
| 239 | |