Skip to content

Instantly share code, notes, and snippets.

@dennwc
Created March 31, 2019 18:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dennwc/de336c848695232aab72c06b943349ab to your computer and use it in GitHub Desktop.
Save dennwc/de336c848695232aab72c06b943349ab to your computer and use it in GitHub Desktop.
# HG changeset patch
# User dennwc@dennwc-ThinkPad-X270
# Date 1554055927 -10800
# Sun Mar 31 21:12:07 2019 +0300
# Branch alpn
# Node ID ffcbdcb6ebb1b074d49a01e18bb2f4f20b8c62f0
# Parent 3f1c58b88912114e43777999b3a2761a893f745e
initial support for alpn
diff -r 3f1c58b88912 -r ffcbdcb6ebb1 dcpp/BufferedSocket.cpp
--- a/dcpp/BufferedSocket.cpp Sun Feb 10 22:15:36 2019 +0100
+++ b/dcpp/BufferedSocket.cpp Sun Mar 31 21:12:07 2019 +0300
@@ -113,7 +113,7 @@
void BufferedSocket::connect(const string& aAddress, const string& aPort, const string& localPort, NatRoles natRole, bool secure, bool allowUntrusted, bool proxy, const string& expKP) {
dcdebug("BufferedSocket::connect() %p\n", (void*)this);
- unique_ptr<Socket> s(secure ? new SSLSocket(natRole == NAT_SERVER ? CryptoManager::SSL_SERVER : CryptoManager::SSL_CLIENT, allowUntrusted, expKP) : new Socket(Socket::TYPE_TCP));
+ unique_ptr<Socket> s(secure ? new SSLSocket(natRole == NAT_SERVER ? CryptoManager::SSL_SERVER : CryptoManager::SSL_CLIENT_ALPN, allowUntrusted, expKP) : new Socket(Socket::TYPE_TCP));
s->setLocalIp4(CONNSETTING(BIND_ADDRESS));
s->setLocalIp6(CONNSETTING(BIND_ADDRESS6));
diff -r 3f1c58b88912 -r ffcbdcb6ebb1 dcpp/CryptoManager.cpp
--- a/dcpp/CryptoManager.cpp Sun Feb 10 22:15:36 2019 +0100
+++ b/dcpp/CryptoManager.cpp Sun Mar 31 21:12:07 2019 +0300
@@ -34,6 +34,11 @@
namespace dcpp {
+unsigned char alpn_protos[] = {
+ 3, 'a', 'd', 'c',
+ 4, 'n', 'm', 'd', 'c',
+};
+
void* CryptoManager::tmpKeysMap[KEY_LAST] = { NULL, NULL, NULL };
CriticalSection* CryptoManager::cs = NULL;
int CryptoManager::idxVerifyData = 0;
@@ -53,11 +58,12 @@
SSL_load_error_strings();
clientContext.reset(SSL_CTX_new(SSLv23_client_method()));
+ clientALPNContext.reset(SSL_CTX_new(SSLv23_client_method()));
serverContext.reset(SSL_CTX_new(SSLv23_server_method()));
idxVerifyData = SSL_get_ex_new_index(0, idxVerifyDataName, NULL, NULL, NULL);
- if(clientContext && serverContext) {
+ if(clientContext && clientALPNContext && serverContext) {
// Check that openssl rng has been seeded with enough data
sslRandCheck();
@@ -72,6 +78,8 @@
const char ciphersuites[] = "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:DHE-RSA-AES128-SHA:AES128-SHA";
SSL_CTX_set_options(clientContext, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION);
SSL_CTX_set_cipher_list(clientContext, ciphersuites);
+ SSL_CTX_set_options(clientALPNContext, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION);
+ SSL_CTX_set_cipher_list(clientALPNContext, ciphersuites);
SSL_CTX_set_options(serverContext, SSL_OP_SINGLE_DH_USE | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION);
SSL_CTX_set_cipher_list(serverContext, ciphersuites);
@@ -87,7 +95,10 @@
SSL_CTX_set_tmp_rsa_callback(serverContext, CryptoManager::tmp_rsa_cb);
SSL_CTX_set_verify(clientContext, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, verify_callback);
+ SSL_CTX_set_verify(clientALPNContext, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, verify_callback);
SSL_CTX_set_verify(serverContext, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, verify_callback);
+
+ SSL_CTX_set_alpn_protos(clientALPNContext, alpn_protos, sizeof(alpn_protos));
}
}
@@ -99,6 +110,7 @@
ERR_remove_thread_state(NULL);
clientContext.reset();
+ clientALPNContext.reset();
serverContext.reset();
for(int i = KEY_FIRST; i != KEY_RSA_2048; ++i) {
@@ -356,7 +368,7 @@
}
void CryptoManager::loadCertificates() noexcept {
- if(!clientContext || !serverContext)
+ if(!clientContext || !clientALPNContext || !serverContext)
return;
keyprint.clear();
@@ -383,7 +395,8 @@
if(
!ssl::SSL_CTX_use_certificate_file(serverContext, cert.c_str(), SSL_FILETYPE_PEM) ||
- !ssl::SSL_CTX_use_certificate_file(clientContext, cert.c_str(), SSL_FILETYPE_PEM)
+ !ssl::SSL_CTX_use_certificate_file(clientContext, cert.c_str(), SSL_FILETYPE_PEM) ||
+ !ssl::SSL_CTX_use_certificate_file(clientALPNContext, cert.c_str(), SSL_FILETYPE_PEM)
) {
LogManager::getInstance()->message(_("Failed to load certificate file"));
return;
@@ -391,7 +404,8 @@
if(
!ssl::SSL_CTX_use_PrivateKey_file(serverContext, key.c_str(), SSL_FILETYPE_PEM) ||
- !ssl::SSL_CTX_use_PrivateKey_file(clientContext, key.c_str(), SSL_FILETYPE_PEM)
+ !ssl::SSL_CTX_use_PrivateKey_file(clientContext, key.c_str(), SSL_FILETYPE_PEM) ||
+ !ssl::SSL_CTX_use_PrivateKey_file(clientALPNContext, key.c_str(), SSL_FILETYPE_PEM)
) {
LogManager::getInstance()->message(_("Failed to load private key"));
return;
@@ -404,6 +418,7 @@
for(auto& i: certs) {
if(
SSL_CTX_load_verify_locations(clientContext, i.c_str(), NULL) != SSL_SUCCESS ||
+ SSL_CTX_load_verify_locations(clientALPNContext, i.c_str(), NULL) != SSL_SUCCESS ||
SSL_CTX_load_verify_locations(serverContext, i.c_str(), NULL) != SSL_SUCCESS
) {
LogManager::getInstance()->message(str(F_("Failed to load trusted certificate from %1%") % Util::addBrackets(i)));
@@ -459,6 +474,7 @@
SSL_CTX* CryptoManager::getSSLContext(SSLContext wanted) {
switch(wanted) {
case SSL_CLIENT: return clientContext;
+ case SSL_CLIENT_ALPN: return clientALPNContext;
case SSL_SERVER: return serverContext;
default: return NULL;
}
diff -r 3f1c58b88912 -r ffcbdcb6ebb1 dcpp/CryptoManager.h
--- a/dcpp/CryptoManager.h Sun Feb 10 22:15:36 2019 +0100
+++ b/dcpp/CryptoManager.h Sun Mar 31 21:12:07 2019 +0300
@@ -50,6 +50,7 @@
enum SSLContext {
SSL_CLIENT,
+ SSL_CLIENT_ALPN,
SSL_SERVER
};
@@ -84,6 +85,7 @@
virtual ~CryptoManager();
ssl::SSL_CTX clientContext;
+ ssl::SSL_CTX clientALPNContext;
ssl::SSL_CTX serverContext;
void sslRandCheck();
diff -r 3f1c58b88912 -r ffcbdcb6ebb1 dcpp/SSLSocket.cpp
--- a/dcpp/SSLSocket.cpp Sun Feb 10 22:15:36 2019 +0100
+++ b/dcpp/SSLSocket.cpp Sun Mar 31 21:12:07 2019 +0300
@@ -67,6 +67,26 @@
if(ret == 1) {
dcdebug("Connected to SSL server using %s as %s\n",
SSL_get_cipher(ssl), SSL_is_server(ssl) ? "server" : "client");
+
+ if (SSL_is_server(ssl)) return true;
+
+ // protocol negotiation (ALPN)
+ const unsigned char* negotiated = 0;
+ unsigned int len = 0;
+ SSL_get0_alpn_selected(ssl, &negotiated, &len);
+ if (len == 0) {
+ // negotiation failed, use default
+ proto = PROTO_DEFAULT;
+ return true
+ }
+ if (len == 3 && !memcmp(negotiated, "adc", len)) {
+ proto = PROTO_ADC;
+ } else if (len == 4 && !memcmp(negotiated, "nmdc", len)) {
+ proto = PROTO_NMDC;
+ } else {
+ proto = PROTO_DEFAULT;
+ }
+ dcdebug("ALPN negotiated %.*s (%d)\n", len, protocol, proto);
return true;
}
if(!waitWant(ret, millis)) {
diff -r 3f1c58b88912 -r ffcbdcb6ebb1 dcpp/Socket.cpp
--- a/dcpp/Socket.cpp Sun Feb 10 22:15:36 2019 +0100
+++ b/dcpp/Socket.cpp Sun Mar 31 21:12:07 2019 +0300
@@ -250,6 +250,10 @@
if(sock6.valid()) setBlocking2(sock6, block);
}
+Protocol Socket::getNextProtocol() noexcept {
+ return proto;
+}
+
socket_t Socket::create(const addrinfo& ai) {
return setSock(check([&] { return ::socket(ai.ai_family, ai.ai_socktype, ai.ai_protocol); }), ai.ai_family);
}
diff -r 3f1c58b88912 -r ffcbdcb6ebb1 dcpp/Socket.h
--- a/dcpp/Socket.h Sun Feb 10 22:15:36 2019 +0100
+++ b/dcpp/Socket.h Sun Mar 31 21:12:07 2019 +0300
@@ -89,7 +89,13 @@
TYPE_UDP = IPPROTO_UDP
};
- explicit Socket(SocketType type) : type(type) { }
+ enum Protocol {
+ PROTO_DEFAULT = 0,
+ PROTO_NMDC = 1,
+ PROTO_ADC = 2
+ }
+
+ explicit Socket(SocketType type) : type(type), proto(PROTO_DEFAULT) { }
virtual ~Socket() { }
@@ -174,6 +180,8 @@
int getSocketOptInt(int option);
void setSocketOpt(int option, int value);
+ Protocol getNextProtocol();
+
virtual bool isSecure() const noexcept { return false; }
virtual bool isTrusted() const noexcept { return false; }
virtual string getCipherName() const noexcept { return Util::emptyString; }
@@ -217,6 +225,8 @@
static addr udpAddr;
static socklen_t udpAddrLen;
+ Protocol proto;
+
private:
void socksAuth(uint32_t timeout);
socket_t setSock(socket_t s, int af);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment