1 /*
2   Copyright (c) DataStax, Inc.
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 DATASTAX_INTERNAL_SSL_HPP
18 #define DATASTAX_INTERNAL_SSL_HPP
19 
20 #include "address.hpp"
21 #include "allocated.hpp"
22 #include "cassandra.h"
23 #include "driver_config.hpp"
24 #include "external.hpp"
25 #include "ref_counted.hpp"
26 #include "ring_buffer.hpp"
27 #include "string.hpp"
28 
29 #include <uv.h>
30 
31 namespace datastax { namespace internal { namespace core {
32 
33 class SslSession : public Allocated {
34 public:
SslSession(const Address & address,const String & hostname,const String & sni_server_name,int flags)35   SslSession(const Address& address, const String& hostname, const String& sni_server_name,
36              int flags)
37       : address_(address)
38       , hostname_(hostname)
39       , sni_server_name_(sni_server_name)
40       , verify_flags_(flags)
41       , error_code_(CASS_OK) {}
42 
~SslSession()43   virtual ~SslSession() {}
44 
has_error() const45   bool has_error() const { return error_code() != CASS_OK; }
46 
error_code() const47   CassError error_code() const { return error_code_; }
48 
error_message() const49   String error_message() const { return error_message_; }
50 
51   virtual bool is_handshake_done() const = 0;
52   virtual void do_handshake() = 0;
53   virtual void verify() = 0;
54 
55   virtual int encrypt(const char* data, size_t data_size) = 0;
56   virtual int decrypt(char* data, size_t data_size) = 0;
57 
incoming()58   rb::RingBuffer& incoming() { return incoming_; }
outgoing()59   rb::RingBuffer& outgoing() { return outgoing_; }
60 
61 protected:
62   Address address_;
63   String hostname_;
64   String sni_server_name_;
65   int verify_flags_;
66   rb::RingBuffer incoming_;
67   rb::RingBuffer outgoing_;
68   CassError error_code_;
69   String error_message_;
70 };
71 
72 class SslContext : public RefCounted<SslContext> {
73 public:
74   typedef SharedRefPtr<SslContext> Ptr;
75 
SslContext()76   SslContext()
77       : verify_flags_(CASS_SSL_VERIFY_PEER_CERT) {}
78 
~SslContext()79   virtual ~SslContext() {}
80 
set_verify_flags(int flags)81   void set_verify_flags(int flags) { verify_flags_ = flags; }
is_cert_validation_enabled()82   bool is_cert_validation_enabled() { return verify_flags_ != CASS_SSL_VERIFY_NONE; }
83 
84   virtual SslSession* create_session(const Address& address, const String& hostname,
85                                      const String& sni_server_name) = 0;
86   virtual CassError add_trusted_cert(const char* cert, size_t cert_length) = 0;
87   virtual CassError set_cert(const char* cert, size_t cert_length) = 0;
88   virtual CassError set_private_key(const char* key, size_t key_length, const char* password,
89                                     size_t password_length) = 0;
90 
91 protected:
92   int verify_flags_;
93 };
94 
95 template <class T>
96 class SslContextFactoryBase {
97 public:
98   static SslContext::Ptr create();
99   static void init_once();
100   static void thread_cleanup();
101 
102   static void init();    // Tests only
103   static void cleanup(); // Tests only
104 
105 private:
106   static uv_once_t ssl_init_guard;
107 };
108 
109 template <class T>
create()110 SslContext::Ptr SslContextFactoryBase<T>::create() {
111   return T::create();
112 }
113 
114 template <class T>
init_once()115 void SslContextFactoryBase<T>::init_once() {
116   uv_once(&ssl_init_guard, T::init);
117 }
118 
119 template <class T>
thread_cleanup()120 void SslContextFactoryBase<T>::thread_cleanup() {
121   T::internal_thread_cleanup();
122 }
123 
124 template <class T>
init()125 void SslContextFactoryBase<T>::init() {
126   T::internal_init();
127 }
128 
129 template <class T>
cleanup()130 void SslContextFactoryBase<T>::cleanup() {
131   T::internal_cleanup();
132 }
133 
134 }}} // namespace datastax::internal::core
135 
136 #ifdef HAVE_OPENSSL
137 #include "ssl/ssl_openssl_impl.hpp"
138 #else
139 #include "ssl/ssl_no_impl.hpp"
140 #endif
141 
142 EXTERNAL_TYPE(datastax::internal::core::SslContext, CassSsl)
143 
144 #endif
145