Skip to content

Commit 3669385

Browse files
committed
add ssl debugging, assume ssl_ctx is global as documented (for #751)
1 parent 2074356 commit 3669385

File tree

2 files changed

+102
-79
lines changed

2 files changed

+102
-79
lines changed

src/lib/utils/httpclient.cpp

+101-74
Original file line numberDiff line numberDiff line change
@@ -83,9 +83,6 @@ bool isError(const char* call, long result, long expected) {
8383

8484
SSLSocket::~SSLSocket() {
8585
BIO_free_all(m_bio);
86-
if (m_ctx) {
87-
SSL_CTX_free(m_ctx);
88-
}
8986
}
9087

9188
ssize_t SSLSocket::send(const char* data, size_t len) {
@@ -142,26 +139,56 @@ bool SSLSocket::isValid() {
142139
return time(nullptr) < m_until && !BIO_eof(m_bio);
143140
}
144141

142+
void sslInfoCallback(const SSL *ssl, int type, int val) {
143+
if (!needsLog(lf_network, (val == 0) ? ll_error : ll_debug)) {
144+
return;
145+
}
146+
logWrite(lf_network,
147+
(val == 0) ? ll_error : ll_debug,
148+
"SSL state %s: type 0x%x=%s%s%s%s%s%s%s%s%s val %d=%s",
149+
SSL_state_string_long(ssl),
150+
type,
151+
(type & SSL_CB_LOOP) ? "loop," : "",
152+
(type & SSL_CB_EXIT) ? "exit," : "",
153+
(type & SSL_CB_READ) ? "read," : "",
154+
(type & SSL_CB_WRITE) ? "write," : "",
155+
(type & SSL_CB_ALERT) ? "alert," : "",
156+
(type & SSL_ST_ACCEPT) ? "accept," : "",
157+
(type & SSL_ST_CONNECT) ? "connect," : "",
158+
(type & SSL_CB_HANDSHAKE_START) ? "start," : "",
159+
(type & SSL_CB_HANDSHAKE_DONE) ? "done," : "",
160+
val,
161+
(type & SSL_CB_ALERT) ? SSL_alert_desc_string_long(val) : "?");
162+
}
163+
145164
SSLSocket* SSLSocket::connect(const string& host, const uint16_t& port, bool https, int timeout, const char* caFile,
146165
const char* caPath) {
147-
BIO *bio = nullptr;
148-
SSL_CTX *ctx = nullptr;
149166
ostringstream ostr;
150167
ostr << host << ':' << static_cast<unsigned>(port);
151168
const string hostPort = ostr.str();
152169
time_t until = time(nullptr) + 1 + (timeout <= 5 ? 5 : timeout); // at least 5 seconds, 1 extra for rounding
153170
if (!https) {
154171
do {
155-
bio = BIO_new_connect(static_cast<const char*>(hostPort.c_str()));
172+
BIO *bio = BIO_new_connect(static_cast<const char*>(hostPort.c_str()));
156173
if (isError("connect", bio != nullptr)) {
157174
break;
158175
}
159176
BIO_set_nbio(bio, 1); // set non-blocking
160-
return new SSLSocket(nullptr, bio, until);
177+
return new SSLSocket(bio, until);
161178
} while (false);
162-
} else {
163-
SSL *ssl = nullptr;
164-
do {
179+
return nullptr;
180+
}
181+
BIO *bio = nullptr;
182+
static SSL_CTX *ctx = nullptr;
183+
static int sslContextInitTries = 0;
184+
do {
185+
// const SSL_METHOD *method = TLS_client_method();
186+
static bool verifyPeer = true;
187+
if (ctx == nullptr) { // according to openssl manpage, ctx is global and should be created once only
188+
if (sslContextInitTries > 2) { // give it up to 3 tries to initialize the context
189+
break;
190+
}
191+
sslContextInitTries++;
165192
const SSL_METHOD *method = SSLv23_method();
166193
if (isError("method", method != nullptr)) {
167194
break;
@@ -170,7 +197,8 @@ SSLSocket* SSLSocket::connect(const string& host, const uint16_t& port, bool htt
170197
if (isError("ctx_new", ctx != nullptr)) {
171198
break;
172199
}
173-
bool verifyPeer = !caFile || strcmp(caFile, "#") != 0;
200+
SSL_CTX_set_info_callback(ctx, sslInfoCallback);
201+
verifyPeer = !caFile || strcmp(caFile, "#") != 0;
174202
SSL_CTX_set_verify(ctx, verifyPeer ? SSL_VERIFY_PEER : SSL_VERIFY_NONE, nullptr);
175203
if (verifyPeer) {
176204
#if OPENSSL_VERSION_NUMBER >= 0x10101000L
@@ -185,79 +213,78 @@ SSLSocket* SSLSocket::connect(const string& host, const uint16_t& port, bool htt
185213
}
186214
#endif
187215
if ((caFile || caPath) && isError("verify_loc", SSL_CTX_load_verify_locations(ctx, caFile, caPath), 1)) {
216+
SSL_CTX_free(ctx);
217+
ctx = nullptr;
188218
break;
189219
}
190220
}
191-
const long flags = SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION;
192-
SSL_CTX_set_options(ctx, flags);
193-
bio = BIO_new_ssl_connect(ctx);
194-
if (isError("new_ssl_conn", bio != nullptr)) {
195-
break;
196-
}
197-
if (isError("conn_hostname", BIO_set_conn_hostname(bio, hostPort.c_str()), 1)) {
198-
break;
199-
}
200-
BIO_set_nbio(bio, 1); // set non-blocking
201-
BIO_get_ssl(bio, &ssl);
202-
if (isError("get_ssl", ssl != nullptr)) {
203-
break;
204-
}
205-
SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
206-
const char *hostname = host.c_str();
207-
if (isError("tls_host", SSL_set_tlsext_host_name(ssl, hostname), 1)) {
208-
break;
209-
}
210-
long res = BIO_do_connect(bio);
211-
time_t now = 0;
212-
while (res <= 0 && (BIO_should_retry(bio) || now == 0)) { // always repeat on first failure
213-
if ((now=time(nullptr)) > until) {
214-
break;
215-
}
216-
usleep(SLEEP_NANOS);
217-
res = BIO_do_connect(bio);
218-
}
219-
if (res <= 0 && now > until) {
220-
logError(lf_network, "HTTP connect: timed out after %d sec", now-until);
221-
break;
222-
}
223-
if (isError("connect", res, 1)) {
224-
break;
225-
}
226-
X509 *cert = SSL_get_peer_certificate(ssl);
227-
if (isError("peer_cert", cert != nullptr)) {
228-
break;
229-
}
230-
X509_free(cert); // decrement reference count incremented by above call
231-
if (verifyPeer && isError("verify", SSL_get_verify_result(ssl), X509_V_OK)) {
232-
break;
233-
}
234-
// check hostname
235-
X509_NAME *sname = X509_get_subject_name(cert);
236-
if (isError("get_subject", sname != nullptr)) {
221+
SSL_CTX_set_options(ctx, SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION);
222+
}
223+
bio = BIO_new_ssl_connect(ctx);
224+
if (isError("new_ssl_conn", bio != nullptr)) {
225+
break;
226+
}
227+
if (isError("conn_hostname", BIO_set_conn_hostname(bio, hostPort.c_str()), 1)) {
228+
break;
229+
}
230+
BIO_set_nbio(bio, 1); // set non-blocking
231+
SSL *ssl = nullptr;
232+
BIO_get_ssl(bio, &ssl);
233+
if (isError("get_ssl", ssl != nullptr)) {
234+
break;
235+
}
236+
SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
237+
const char *hostname = host.c_str();
238+
if (isError("tls_host", SSL_set_tlsext_host_name(ssl, hostname), 1)) {
239+
break;
240+
}
241+
long res = BIO_do_connect(bio);
242+
time_t now = 0;
243+
while (res <= 0 && (BIO_should_retry(bio) || now == 0)) { // always repeat on first failure
244+
if ((now=time(nullptr)) > until) {
237245
break;
238246
}
239-
char peerName[64];
240-
if (isError("subject name", X509_NAME_get_text_by_NID(sname, NID_commonName, peerName, sizeof(peerName)) > 0)) {
247+
usleep(SLEEP_NANOS);
248+
res = BIO_do_connect(bio);
249+
}
250+
if (res <= 0 && now > until) {
251+
logError(lf_network, "HTTP connect: timed out after %d sec", now-until);
252+
break;
253+
}
254+
if (isError("connect", res, 1)) {
255+
break;
256+
}
257+
X509 *cert = SSL_get_peer_certificate(ssl);
258+
if (isError("peer_cert", cert != nullptr)) {
259+
break;
260+
}
261+
X509_free(cert); // decrement reference count incremented by above call
262+
if (verifyPeer && isError("verify", SSL_get_verify_result(ssl), X509_V_OK)) {
263+
break;
264+
}
265+
// check hostname
266+
X509_NAME *sname = X509_get_subject_name(cert);
267+
if (isError("get_subject", sname != nullptr)) {
268+
break;
269+
}
270+
char peerName[64];
271+
if (isError("subject name", X509_NAME_get_text_by_NID(sname, NID_commonName, peerName, sizeof(peerName)) > 0)) {
272+
break;
273+
}
274+
if (strcmp(peerName, hostname) != 0) {
275+
char* dotpos = NULL;
276+
if (peerName[0] == '*' && peerName[1] == '.' && (dotpos=strchr((char*)hostname, '.'))
277+
&& strcmp(peerName+2, dotpos+1) == 0) {
278+
// wildcard matches
279+
} else if (isError("subject", 1, 0)) {
241280
break;
242281
}
243-
if (strcmp(peerName, hostname) != 0) {
244-
char* dotpos = NULL;
245-
if (peerName[0] == '*' && peerName[1] == '.' && (dotpos=strchr((char*)hostname, '.'))
246-
&& strcmp(peerName+2, dotpos+1) == 0) {
247-
// wildcard matches
248-
} else if (isError("subject", 1, 0)) {
249-
break;
250-
}
251-
}
252-
return new SSLSocket(ctx, bio, until);
253-
} while (false);
254-
}
282+
}
283+
return new SSLSocket(bio, until);
284+
} while (false);
255285
if (bio) {
256286
BIO_free_all(bio);
257287
}
258-
if (ctx) {
259-
SSL_CTX_free(ctx);
260-
}
261288
return nullptr;
262289
}
263290

src/lib/utils/httpclient.h

+1-5
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,10 @@ class SSLSocket {
4949
private:
5050
/**
5151
* Constructor.
52-
* @param ctx the SSL_CTX for cleanup, or nullptr.
5352
* @param bio the BIO instance, or nullptr.
5453
* @param until the system time until the socket is allowed to be used.
5554
*/
56-
SSLSocket(SSL_CTX *ctx, BIO *bio, time_t until) : m_ctx(ctx), m_bio(bio), m_until(until) {}
55+
SSLSocket(BIO *bio, time_t until) : m_bio(bio), m_until(until) {}
5756

5857
public:
5958
/**
@@ -97,9 +96,6 @@ class SSLSocket {
9796
bool isValid();
9897

9998
private:
100-
/** the SSL_CTX for cleanup, or nullptr. */
101-
SSL_CTX *m_ctx;
102-
10399
/** the BIO instance for communication. */
104100
BIO *m_bio;
105101

0 commit comments

Comments
 (0)