TDME2  1.9.200
SecureTCPSocket.cpp
Go to the documentation of this file.
2 
3 #include <openssl/x509.h>
4 #include <openssl/ssl.h>
5 #include <openssl/err.h>
6 #include <openssl/pem.h>
7 #include <openssl/rand.h>
8 #include <openssl/ocsp.h>
9 #include <openssl/bn.h>
10 #include <openssl/trace.h>
11 #include <openssl/async.h>
12 #ifndef OPENSSL_NO_CT
13 #include <openssl/ct.h>
14 #endif
15 
16 #include <string>
17 
18 #include <tdme/tdme.h>
25 #include <tdme/utilities/Console.h>
26 
28 
29 using std::string;
30 using std::to_string;
31 
39 
40 // see: https://wiki.openssl.org/index.php/SSL/TLS_Client
41 
42 SecureTCPSocket::SecureTCPSocket() {
43 }
44 
46 }
47 
48 size_t SecureTCPSocket::read(void* buf, const size_t bytes) {
49  auto bytesRead = BIO_read(bio, buf, bytes);
50  if (bytesRead == -1) {
51  throw NetworkIOException("Error while reading from socket: " + openSSLGetErrors());
52  } else
53  if (bytesRead == 0) {
54  throw NetworkSocketClosedException("end of stream");
55  }
56  //
57  return (size_t)bytesRead;
58 }
59 
60 size_t SecureTCPSocket::write(void* buf, const size_t bytes) {
61  auto bytesWritten = BIO_write(bio, buf, bytes);
62  if (bytesWritten == -1) {
63  throw NetworkIOException("Error while writing to socket: " + openSSLGetErrors());
64  }
65  //
66  return (size_t)bytesWritten;
67 }
68 
69 void SecureTCPSocket::connect(const string& hostname, const unsigned int port) {
70  // set address
71  this->ip = Network::getIpByHostname(hostname);
72  this->port = port;
73  //
74  const SSL_METHOD* method = SSLv23_method();
75  if (!(nullptr != method))
76  throw NetworkSocketException("Could not connect socket: " + openSSLGetErrors());
77 
78  ctx = SSL_CTX_new(method);
79  if (!(ctx != nullptr))
80  throw NetworkSocketException("Could not connect socket: " + openSSLGetErrors());
81 
82  /* Cannot fail ??? */
83  SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, openSSLVerifyCallback);
84 
85  /* Cannot fail ??? */
86  SSL_CTX_set_verify_depth(ctx, 4);
87 
88  /* Cannot fail ??? */
89  const long flags = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION;
90  SSL_CTX_set_options(ctx, flags);
91 
92  //
93  long result = 1;
94  // see: https://stackoverflow.com/questions/59017890/where-is-the-certificate-file-for-ssl-ctx-load-verify-locations-in-openssl-locat
95  result = SSL_CTX_load_verify_locations(ctx, "resources/certs/cacert-2023-08-22.pem" /* truststore */, "resources/certs");
96  if (!(1 == result))
97  throw NetworkSocketException("Could not connect socket: " + openSSLGetErrors());
98 
99  bio = BIO_new_ssl_connect(ctx);
100  if (!(bio != nullptr))
101  throw NetworkSocketException("Could not connect socket: " + openSSLGetErrors());
102 
103  result = BIO_set_conn_hostname(bio, string(hostname + ":" + to_string(port)).c_str());
104  if (!(1 == result))
105  throw NetworkSocketException("Could not connect socket: " + openSSLGetErrors());
106 
107  BIO_get_ssl(bio, &ssl);
108  if (!(ssl != nullptr))
109  throw NetworkSocketException("Could not connect socket: " + openSSLGetErrors());
110 
111  const char PREFERRED_CIPHERS[] = "HIGH:!aNULL:!kRSA:!PSK:!SRP:!MD5:!RC4";
112  result = SSL_set_cipher_list(ssl, PREFERRED_CIPHERS);
113  if (!(1 == result))
114  throw NetworkSocketException("Could not connect socket: " + openSSLGetErrors());
115 
116  result = SSL_set_tlsext_host_name(ssl, hostname.c_str());
117  if (!(1 == result))
118  throw NetworkSocketException("Could not connect socket: " + openSSLGetErrors());
119 
120  out = BIO_new_fp(stdout, BIO_NOCLOSE);
121  if (!(nullptr != out))
122  throw NetworkSocketException("Could not connect socket: " + openSSLGetErrors());
123 
124  result = BIO_do_connect(bio);
125  if (!(1 == result))
126  throw NetworkSocketException("Could not connect socket: " + openSSLGetErrors());
127 
128  result = BIO_do_handshake(bio);
129  if (!(1 == result))
130  throw NetworkSocketException("Could not connect socket: " + openSSLGetErrors());
131 
132  /* Step 1: verify a server certificate was presented during the negotiation */
133  X509* cert = SSL_get_peer_certificate(ssl);
134  if (cert) {
135  X509_free(cert);
136  } /* Free immediately */
137  if (nullptr == cert)
138  throw NetworkSocketException("Could not connect socket: " + openSSLGetErrors());
139 
140  /* Step 2: verify the result of chain verification */
141  /* Verification performed according to RFC 4158 */
142  result = SSL_get_verify_result(ssl);
143  if (!(X509_V_OK == result))
144  throw NetworkSocketException("Could not connect socket: " + openSSLGetErrors());
145 }
146 
148  if (bio != nullptr) BIO_free_all(bio);
149  if (ctx != nullptr) SSL_CTX_free(ctx);
150  bio = nullptr;
151  ctx = nullptr;
152 }
153 
155  if (bio != nullptr) BIO_free_all(bio);
156  if (ctx != nullptr) SSL_CTX_free(ctx);
157  bio = nullptr;
158  ctx = nullptr;
159 }
160 
161 int SecureTCPSocket::openSSLVerifyCallback(int preverify, X509_STORE_CTX *x509_ctx) {
162  int depth = X509_STORE_CTX_get_error_depth(x509_ctx);
163  int err = X509_STORE_CTX_get_error(x509_ctx);
164  X509 *cert = X509_STORE_CTX_get_current_cert(x509_ctx);
165  X509_NAME *iname = cert ? X509_get_issuer_name(cert) : nullptr;
166  X509_NAME *sname = cert ? X509_get_subject_name(cert) : nullptr;
167  /*
168  print_cn_name("Issuer (cn)", iname);
169  print_cn_name("Subject (cn)", sname);
170  */
171  if (depth == 0) {
172  /* If depth is 0, its the server's certificate. Print the SANs too */
173  /*
174  print_san_name("Subject (san)", cert);
175  */
176  }
177  return preverify;
178 }
179 
181  string result;
182  int err;
183  while (err = ERR_get_error()) {
184  auto errorMessage = ERR_error_string(err, 0);
185  if (errorMessage == nullptr) return result;
186  result+= string(errorMessage) + "\n";
187  }
188  return result;
189 }
Base exception class for network IO exceptions.
Base class of network sockets.
Definition: NetworkSocket.h:17
Network class.
Definition: Network.h:14
static const string getIpByHostname(const string &hostname)
Get IP by hostname.
Definition: Network.cpp:51
Class representing a secure TCP socket.
static int openSSLVerifyCallback(int preverify, X509_STORE_CTX *x509_ctx)
OpenSSL verify callback.
size_t read(void *buf, const size_t bytes)
Reads up to "bytes" bytes from socket.
size_t write(void *buf, const size_t bytes)
Writes up to "bytes" bytes to socket.
virtual void close()
Closes the socket.
virtual void shutdown()
shuts socket down for reading and writing
void connect(const string &hostname, const unsigned int port)
Connects a socket to given remote IP and port.
virtual ~SecureTCPSocket()
Public destructor.
Mutex implementation.
Definition: Mutex.h:19
Console class.
Definition: Console.h:29