CCF
Loading...
Searching...
No Matches
tls_client.h
Go to the documentation of this file.
1// Copyright (c) Microsoft Corporation. All rights reserved.
2// Licensed under the Apache 2.0 License.
3#pragma once
4
6#include "ccf/ds/logger.h"
7#include "tls/ca.h"
8#include "tls/cert.h"
9
10#include <cstdint>
11#include <cstring>
12#include <iostream>
13#include <netinet/in.h>
14#include <netinet/tcp.h>
15#include <openssl/bio.h>
16#include <string>
17#include <vector>
18
19using namespace ccf::crypto::OpenSSL;
20
21#ifdef _DEBUG
22static BIO* bio_err = NULL;
23
24static void apps_ssl_info_callback(const SSL* s, int where, int ret)
25{
26 const char* str;
27 int w = where & ~SSL_ST_MASK;
28
29 if (w & SSL_ST_CONNECT)
30 str = "SSL_connect";
31 else if (w & SSL_ST_ACCEPT)
32 str = "SSL_accept";
33 else
34 str = "undefined";
35
36 if (where & SSL_CB_LOOP)
37 {
38 BIO_printf(bio_err, "%s:%s\n", str, SSL_state_string_long(s));
39 }
40 else if (where & SSL_CB_ALERT)
41 {
42 str = (where & SSL_CB_READ) ? "read" : "write";
43 BIO_printf(
44 bio_err,
45 "SSL3 alert %s:%s:%s\n",
46 str,
47 SSL_alert_type_string_long(ret),
48 SSL_alert_desc_string_long(ret));
49 }
50 else if (where & SSL_CB_EXIT)
51 {
52 if (ret == 0)
53 {
54 BIO_printf(bio_err, "%s:failed in %s\n", str, SSL_state_string_long(s));
55 }
56 else if (ret < 0)
57 {
58 BIO_printf(bio_err, "%s:error in %s\n", str, SSL_state_string_long(s));
59 }
60 }
61}
62#endif
63
64namespace client
65{
67 {
68 protected:
69 std::string host;
70 std::string port;
71 std::shared_ptr<::tls::CA> node_ca;
72 std::shared_ptr<::tls::Cert> cert;
73 bool connected = false;
74
77
78 void init()
79 {
80 SSL_CTX_clear_mode(ctx, SSL_MODE_AUTO_RETRY);
81
82 SSL* ssl;
83 BIO_get_ssl(bio, &ssl);
84 if (!ssl)
85 {
86 throw std::runtime_error("Couldn't locate SSL pointer");
87 }
88 SSL_clear_mode(ssl, SSL_MODE_AUTO_RETRY);
89
90#ifdef _DEBUG
91 bio_err = BIO_new_fp(stdout, BIO_NOCLOSE);
92 SSL_CTX_set_info_callback(ctx, apps_ssl_info_callback);
93 SSL_set_info_callback(ssl, apps_ssl_info_callback);
94#endif
95
96 BIO_set_conn_hostname(bio, host.c_str());
97 BIO_set_conn_port(bio, port.c_str());
98 BIO_set_nbio(bio, 1);
99
100 if (cert)
101 cert->use(ssl, ctx);
102 if (node_ca)
103 node_ca->use(ctx);
104
105 do
106 {
107 BIO_do_connect(bio);
108 } while (BIO_should_retry(bio));
109
110 do
111 {
112 BIO_do_handshake(bio);
113 } while (BIO_should_retry(bio));
114
115 connected = true;
116 }
117
118 public:
120 const std::string& host,
121 const std::string& port,
122 std::shared_ptr<::tls::CA> node_ca = nullptr,
123 std::shared_ptr<::tls::Cert> cert = nullptr) :
124 host(host),
125 port(port),
127 cert(cert),
128 ctx(TLS_client_method()),
129 bio(ctx)
130 {
131 init();
132 }
133
135 host(c.host),
136 port(c.port),
137 node_ca(c.node_ca),
138 cert(c.cert),
139 ctx(TLS_client_method()),
140 bio(ctx)
141 {
142 init();
143 }
144
145 virtual ~TlsClient()
146 {
147 SSL* ssl;
148 BIO_get_ssl(bio, &ssl);
149 SSL_shutdown(ssl);
150 }
151
153 {
154 SSL* ssl;
155 BIO_get_ssl(bio, &ssl);
156 return SSL_CIPHER_get_name(SSL_get_current_cipher(ssl));
157 }
158
159 void write(std::span<const uint8_t> b)
160 {
161 for (size_t written = 0; written < b.size();)
162 {
163 auto ret = 0;
164 do
165 {
166 ret = BIO_write(bio, b.data() + written, b.size() - written);
167 } while (ret < 0 && BIO_should_retry(bio));
168
169 if (ret >= 0)
170 {
171 written += ret;
172 }
173 else
174 {
175 throw std::logic_error(error_string(ERR_get_error()));
176 }
177 }
178 }
179
180 std::vector<uint8_t> read(size_t read_size)
181 {
182 std::vector<uint8_t> buf(read_size);
183
184 auto ret = 0;
185 do
186 {
187 ret = BIO_read(bio, buf.data(), buf.size());
188 } while (ret < 0 && BIO_should_retry(bio));
189
190 if (ret > 0)
191 {
192 buf.resize(ret);
193 }
194 else if (ret == 0)
195 {
196 connected = false;
197 throw std::logic_error("Underlying transport closed");
198 }
199 else
200 {
201 throw std::logic_error(error_string(ERR_get_error()));
202 }
203
204 return buf;
205 }
206
208 {
209 return BIO_pending(bio) > 0;
210 }
211
212 std::vector<uint8_t> read_all()
213 {
214 constexpr auto read_size = 4096;
215 return read(read_size);
216 }
217
218 void set_tcp_nodelay(bool on)
219 {
220 int option = on ? 1 : 0;
221 int fd = -1;
222 BIO_get_fd(bio, &fd);
223 setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char*)&option, sizeof(int));
224 }
225 };
226}
Definition tls_client.h:67
std::vector< uint8_t > read_all()
Definition tls_client.h:212
std::string port
Definition tls_client.h:70
std::shared_ptr<::tls::CA > node_ca
Definition tls_client.h:71
auto get_ciphersuite_name()
Definition tls_client.h:152
Unique_BIO bio
Definition tls_client.h:76
TlsClient(const TlsClient &c)
Definition tls_client.h:134
bool bytes_available()
Definition tls_client.h:207
std::shared_ptr<::tls::Cert > cert
Definition tls_client.h:72
virtual ~TlsClient()
Definition tls_client.h:145
bool connected
Definition tls_client.h:73
std::string host
Definition tls_client.h:69
void set_tcp_nodelay(bool on)
Definition tls_client.h:218
std::vector< uint8_t > read(size_t read_size)
Definition tls_client.h:180
TlsClient(const std::string &host, const std::string &port, std::shared_ptr<::tls::CA > node_ca=nullptr, std::shared_ptr<::tls::Cert > cert=nullptr)
Definition tls_client.h:119
void init()
Definition tls_client.h:78
void write(std::span< const uint8_t > b)
Definition tls_client.h:159
Unique_SSL_CTX ctx
Definition tls_client.h:75
Definition openssl_wrappers.h:29
std::string error_string(unsigned long ec)
Returns the error string from an error code.
Definition openssl_wrappers.h:35
Definition perf_client.h:12
Definition configuration.h:14
Definition openssl_wrappers.h:161
Definition openssl_wrappers.h:184