forked from yedf2/handy-ssl
-
Notifications
You must be signed in to change notification settings - Fork 0
/
ssl-conn.cc
146 lines (133 loc) · 4.64 KB
/
ssl-conn.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#include "ssl-conn.h"
#include <assert.h>
#include <poll.h>
//#define SSL_ERROR_NONE 0
//#define SSL_ERROR_SSL 1
//#define SSL_ERROR_WANT_READ 2
//#define SSL_ERROR_WANT_WRITE 3
//#define SSL_ERROR_WANT_X509_LOOKUP 4
//#define SSL_ERROR_SYSCALL 5
//#define SSL_ERROR_ZERO_RETURN 6
//#define SSL_ERROR_WANT_CONNECT 7
//#define SSL_ERROR_WANT_ACCEPT 8
using namespace std;
namespace handy {
namespace {
static BIO* errBio;
static SSL_CTX* g_sslCtx;
void safeSSLInit() {
static int forinit = [] {
// Register the error strings for libcrypto & libssl
SSL_load_error_strings ();
// Register the available ciphers and digests
int r = SSL_library_init ();
fatalif(!r, "SSL_library_init failed");
g_sslCtx = SSL_CTX_new (SSLv23_method ());
fatalif(g_sslCtx == NULL, "SSL_CTX_new failed");
errBio = BIO_new_fd(Logger::getLogger().getFd(), BIO_NOCLOSE);
static ExitCaller freeBio([]{
BIO_free(errBio);
SSL_CTX_free(g_sslCtx);
ERR_free_strings();
});
trace("ssl library inited");
return 0;
}();
(void)forinit;
}
}
SSLConn::SSLConn():
TcpConn(), ssl_(NULL), tcpConnected_(false) {
safeSSLInit();
}
SSLConn::~SSLConn() {
if (ssl_) {
SSL_shutdown (ssl_);
SSL_free(ssl_);
}
}
int SSLConn::handleHandshake(const TcpConnPtr& con) {
fatalif(state_ != State::Handshaking, "unexpect state %d", state_);
if (!tcpConnected_) {
struct pollfd pfd;
pfd.fd = channel_->fd();
pfd.events = POLLOUT | POLLERR;
int r = poll(&pfd, 1, 0);
if (r == 1 && pfd.revents == POLLOUT) {
channel_->enableReadWrite(true, true);
trace("tcp connected %s - %s fd %d",
local_.toString().c_str(), peer_.toString().c_str(), channel_->fd());
tcpConnected_ = true;
} else {
trace("poll fd %d return %d revents %d", channel_->fd(), r, pfd.revents);
cleanup(con);
return -1;
}
}
if (ssl_ == NULL) {
ssl_ = SSL_new (g_sslCtx);
fatalif(ssl_ == NULL, "SSL_new failed");
int r = SSL_set_fd(ssl_, channel_->fd());
fatalif(!r, "SSL_set_fd failed");
if (isClient()) {
trace("SSL_set_connect_state for channel %ld fd %d", (long)channel_->id(), channel_->fd());
SSL_set_connect_state(ssl_);
} else {
trace("SSL_set_accept_state for channel %ld fd %d", (long)channel_->id(), channel_->fd());
SSL_set_accept_state(ssl_);
}
}
int r = SSL_do_handshake(ssl_);
if (r == 1) {
state_ = State::Connected;
trace("ssl connected %s - %s fd %d",
local_.toString().c_str(), peer_.toString().c_str(), channel_->fd());
if (statecb_) {
statecb_(con);
}
return 0;
}
int err = SSL_get_error(ssl_, r);
if (err == SSL_ERROR_WANT_WRITE) {
if (!channel_->writeEnabled())
channel_->enableWrite(true);
} else if (err == SSL_ERROR_WANT_READ) {
if (channel_->writeEnabled())
channel_->enableWrite(false);
} else {
error("SSL_do_handshake return %d error %d errno %d msg %s", r, err, errno, strerror(errno));
ERR_print_errors(errBio);
cleanup(con);
return -1;
}
return 0;
}
int SSLConn::readImp(int fd, void* buf, size_t bytes) {
int rd = SSL_read(ssl_, buf, bytes);
int ssle = SSL_get_error(ssl_, rd);
if (rd < 0 && ssle != SSL_ERROR_WANT_READ) {
error("SSL_read return %d error %d errno %d msg %s", rd, ssle, errno, strerror(errno));
}
return rd;
}
int SSLConn::writeImp(int fd, const void* buf, size_t bytes) {
int wd = SSL_write(ssl_, buf, bytes);
int ssle = SSL_get_error(ssl_, wd);
if (wd < 0 && ssle != SSL_ERROR_WANT_WRITE) {
error("SSL_write return %d error %d errno %d msg %s", wd, ssle, errno, strerror(errno));
}
return wd;
}
bool SSLConn::certKeyInited_ = false;
void SSLConn::setSSLCertKey(const std::string& cert, const std::string& key) {
safeSSLInit();
int r = SSL_CTX_use_certificate_file(g_sslCtx, cert.c_str(), SSL_FILETYPE_PEM);
fatalif(r<=0, "SSL_CTX_use_certificate_file %s failed", cert.c_str());
r = SSL_CTX_use_PrivateKey_file(g_sslCtx, key.c_str(), SSL_FILETYPE_PEM);
fatalif(r<=0, "SSL_CTX_use_PrivateKey_file %s failed", key.c_str());
r = SSL_CTX_check_private_key(g_sslCtx);
fatalif(!r, "SSL_CTX_check_private_key failed");
trace("ssl cert %s key %s", cert.c_str(), key.c_str());
certKeyInited_ = true;
}
};