mirror of https://gitee.com/bigwinds/arangodb
699 lines
20 KiB
C++
699 lines
20 KiB
C++
////////////////////////////////////////////////////////////////////////////////
|
|
/// DISCLAIMER
|
|
///
|
|
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
|
|
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
|
|
///
|
|
/// Licensed under the Apache License, Version 2.0 (the "License");
|
|
/// you may not use this file except in compliance with the License.
|
|
/// You may obtain a copy of the License at
|
|
///
|
|
/// http://www.apache.org/licenses/LICENSE-2.0
|
|
///
|
|
/// Unless required by applicable law or agreed to in writing, software
|
|
/// distributed under the License is distributed on an "AS IS" BASIS,
|
|
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
/// See the License for the specific language governing permissions and
|
|
/// limitations under the License.
|
|
///
|
|
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
|
|
///
|
|
/// @author Dr. Frank Celler
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "ApplicationEndpointServer.h"
|
|
|
|
#include <openssl/err.h>
|
|
|
|
#include "Basics/FileUtils.h"
|
|
#include "Basics/RandomGenerator.h"
|
|
#include "Basics/ReadLocker.h"
|
|
#include "Basics/VelocyPackHelper.h"
|
|
#include "Basics/WriteLocker.h"
|
|
#include "Basics/ssl-helper.h"
|
|
#include "Dispatcher/ApplicationDispatcher.h"
|
|
#include "HttpServer/HttpHandlerFactory.h"
|
|
#include "HttpServer/HttpServer.h"
|
|
#include "HttpServer/HttpsServer.h"
|
|
#include "Logger/Logger.h"
|
|
#include "Rest/Version.h"
|
|
#include "Scheduler/ApplicationScheduler.h"
|
|
|
|
#include <velocypack/Iterator.h>
|
|
#include <velocypack/velocypack-aliases.h>
|
|
|
|
using namespace arangodb::basics;
|
|
using namespace arangodb::rest;
|
|
|
|
namespace {
|
|
class BIOGuard {
|
|
public:
|
|
explicit BIOGuard(BIO* bio) : _bio(bio) {}
|
|
|
|
~BIOGuard() { BIO_free(_bio); }
|
|
|
|
public:
|
|
BIO* _bio;
|
|
};
|
|
}
|
|
|
|
ApplicationEndpointServer::ApplicationEndpointServer(
|
|
ApplicationServer* applicationServer,
|
|
ApplicationScheduler* applicationScheduler,
|
|
ApplicationDispatcher* applicationDispatcher, AsyncJobManager* jobManager,
|
|
std::string const& authenticationRealm,
|
|
HttpHandlerFactory::context_fptr setContext, void* contextData)
|
|
: ApplicationFeature("EndpointServer"),
|
|
_applicationServer(applicationServer),
|
|
_applicationScheduler(applicationScheduler),
|
|
_applicationDispatcher(applicationDispatcher),
|
|
_jobManager(jobManager),
|
|
_authenticationRealm(authenticationRealm),
|
|
_setContext(setContext),
|
|
_contextData(contextData),
|
|
_handlerFactory(nullptr),
|
|
_servers(),
|
|
_basePath(),
|
|
_endpointList(),
|
|
_httpPort(),
|
|
_endpoints(),
|
|
_reuseAddress(true),
|
|
_keepAliveTimeout(300.0),
|
|
_defaultApiCompatibility(0),
|
|
_allowMethodOverride(false),
|
|
_backlogSize(64),
|
|
_httpsKeyfile(),
|
|
_cafile(),
|
|
_sslProtocol(TLS_V1),
|
|
_sslCache(false),
|
|
_sslOptions(
|
|
(long)(SSL_OP_TLS_ROLLBACK_BUG | SSL_OP_CIPHER_SERVER_PREFERENCE)),
|
|
_sslEcdhCurve("prime256v1"),
|
|
_sslCipherList(""),
|
|
_sslContext(nullptr),
|
|
_rctx() {
|
|
// if our default value is too high, we'll use half of the max value provided
|
|
// by the system
|
|
if (_backlogSize > SOMAXCONN) {
|
|
_backlogSize = SOMAXCONN / 2;
|
|
}
|
|
|
|
_defaultApiCompatibility = Version::getNumericServerVersion();
|
|
}
|
|
|
|
ApplicationEndpointServer::~ApplicationEndpointServer() {
|
|
// ..........................................................................
|
|
// Where ever possible we should EXPLICITLY write down the type used in
|
|
// a templated class/method etc. This makes it a lot easier to debug the
|
|
// code. Granted however, that explicitly writing down the type for an
|
|
// overloaded class operator is a little unwieldy.
|
|
// ..........................................................................
|
|
|
|
for (auto& it : _servers) {
|
|
delete it;
|
|
}
|
|
_servers.clear();
|
|
|
|
delete _handlerFactory;
|
|
|
|
if (_sslContext != nullptr) {
|
|
SSL_CTX_free(_sslContext);
|
|
_sslContext = nullptr;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief builds the endpoint servers
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
bool ApplicationEndpointServer::buildServers() {
|
|
TRI_ASSERT(_handlerFactory != nullptr);
|
|
TRI_ASSERT(_applicationScheduler->scheduler() != nullptr);
|
|
|
|
HttpServer* server;
|
|
|
|
// unencrypted endpoints
|
|
server = new HttpServer(_applicationScheduler->scheduler(),
|
|
_applicationDispatcher->dispatcher(), _handlerFactory,
|
|
_jobManager, _keepAliveTimeout);
|
|
|
|
server->setEndpointList(&_endpointList);
|
|
_servers.push_back(server);
|
|
|
|
// ssl endpoints
|
|
if (_endpointList.hasSsl()) {
|
|
// check the ssl context
|
|
if (_sslContext == nullptr) {
|
|
LOG(INFO) << "please use the --server.keyfile option";
|
|
LOG(FATAL) << "no ssl context is known, cannot create https server";
|
|
FATAL_ERROR_EXIT();
|
|
}
|
|
|
|
// https
|
|
server =
|
|
new HttpsServer(_applicationScheduler->scheduler(),
|
|
_applicationDispatcher->dispatcher(), _handlerFactory,
|
|
_jobManager, _keepAliveTimeout, _sslContext);
|
|
|
|
server->setEndpointList(&_endpointList);
|
|
_servers.push_back(server);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void ApplicationEndpointServer::setupOptions(
|
|
std::map<std::string, ProgramOptionsDescription>& options) {
|
|
// issue #175: add deprecated hidden option for downwards compatibility
|
|
options["Hidden Options"]("server.http-port", &_httpPort,
|
|
"http port for client requests (deprecated)");
|
|
|
|
options["Server Options:help-default"]("server.endpoint", &_endpoints,
|
|
"endpoint for client requests (e.g. "
|
|
"\"tcp://127.0.0.1:8529\", or "
|
|
"\"ssl://192.168.1.1:8529\")");
|
|
|
|
options["Server Options:help-admin"](
|
|
"server.allow-method-override", &_allowMethodOverride,
|
|
"allow HTTP method override using special headers")(
|
|
"server.backlog-size", &_backlogSize, "listen backlog size")(
|
|
"server.default-api-compatibility", &_defaultApiCompatibility,
|
|
"default API compatibility version")("server.keep-alive-timeout",
|
|
&_keepAliveTimeout,
|
|
"keep-alive timeout in seconds")(
|
|
"server.reuse-address", &_reuseAddress, "try to reuse address");
|
|
|
|
options["SSL Options:help-ssl"]("server.keyfile", &_httpsKeyfile,
|
|
"keyfile for SSL connections")(
|
|
"server.cafile", &_cafile,
|
|
"file containing the CA certificates of clients")(
|
|
"server.ssl-protocol", &_sslProtocol,
|
|
"1 = SSLv2, 2 = SSLv23, 3 = SSLv3, 4 = TLSv1, 5 = TLSV1.2 (recommended)")(
|
|
"server.ssl-cache", &_sslCache, "use SSL session caching")(
|
|
"server.ssl-options", &_sslOptions,
|
|
"SSL options, see OpenSSL documentation")(
|
|
"server.ssl-ecdh-curve", &_sslEcdhCurve,
|
|
"SSL ECDH Curve, see the output of \"openssl ecparam -list_curves\"")(
|
|
"server.ssl-cipher-list", &_sslCipherList,
|
|
"SSL cipher list, see OpenSSL documentation");
|
|
}
|
|
|
|
bool ApplicationEndpointServer::afterOptionParsing(ProgramOptions& options) {
|
|
// create the ssl context (if possible)
|
|
bool ok = createSslContext();
|
|
|
|
if (!ok) {
|
|
return false;
|
|
}
|
|
|
|
if (_backlogSize <= 0) {
|
|
LOG(FATAL) << "invalid value for --server.backlog-size. expecting a "
|
|
"positive value";
|
|
FATAL_ERROR_EXIT();
|
|
}
|
|
|
|
if (_backlogSize > SOMAXCONN) {
|
|
LOG(WARN) << "value for --server.backlog-size exceeds default system "
|
|
"header SOMAXCONN value "
|
|
<< SOMAXCONN << ". trying to use " << SOMAXCONN << " anyway";
|
|
}
|
|
|
|
if (!_httpPort.empty()) {
|
|
// issue #175: add hidden option --server.http-port for
|
|
// downwards-compatibility
|
|
std::string httpEndpoint("tcp://" + _httpPort);
|
|
_endpoints.push_back(httpEndpoint);
|
|
}
|
|
|
|
// add & validate endpoints
|
|
for (std::vector<std::string>::const_iterator i = _endpoints.begin();
|
|
i != _endpoints.end(); ++i) {
|
|
bool ok = _endpointList.add((*i), _backlogSize, _reuseAddress);
|
|
|
|
if (!ok) {
|
|
LOG(FATAL) << "invalid endpoint '" << (*i) << "'";
|
|
FATAL_ERROR_EXIT();
|
|
}
|
|
}
|
|
|
|
if (_defaultApiCompatibility < GeneralRequest::MIN_COMPATIBILITY) {
|
|
LOG(FATAL) << "invalid value for --server.default-api-compatibility. "
|
|
"minimum allowed value is "
|
|
<< GeneralRequest::MIN_COMPATIBILITY;
|
|
FATAL_ERROR_EXIT();
|
|
}
|
|
|
|
// and return
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief return a list of all endpoints
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
std::vector<std::string> ApplicationEndpointServer::getEndpoints() {
|
|
return _endpointList.all();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief get the list of databases for an endpoint
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
bool ApplicationEndpointServer::prepare() {
|
|
if (_disabled) {
|
|
return true;
|
|
}
|
|
|
|
if (_endpointList.empty()) {
|
|
LOG(INFO) << "please use the '--server.endpoint' option";
|
|
LOG(FATAL) << "no endpoints have been specified, giving up";
|
|
FATAL_ERROR_EXIT();
|
|
}
|
|
|
|
// dump all endpoints for user information
|
|
_endpointList.dump();
|
|
|
|
_handlerFactory =
|
|
new HttpHandlerFactory(_authenticationRealm, _defaultApiCompatibility,
|
|
_allowMethodOverride, _setContext, _contextData);
|
|
|
|
LOG(DEBUG) << "using default API compatibility: "
|
|
<< (long int)_defaultApiCompatibility;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ApplicationEndpointServer::open() {
|
|
if (_disabled) {
|
|
return true;
|
|
}
|
|
|
|
for (auto& server : _servers) {
|
|
server->startListening();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void ApplicationEndpointServer::close() {
|
|
if (_disabled) {
|
|
return;
|
|
}
|
|
|
|
// close all listen sockets
|
|
for (auto& server : _servers) {
|
|
server->stopListening();
|
|
}
|
|
}
|
|
|
|
void ApplicationEndpointServer::stop() {
|
|
if (_disabled) {
|
|
return;
|
|
}
|
|
|
|
for (auto& server : _servers) {
|
|
server->stop();
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief creates an ssl context
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
bool ApplicationEndpointServer::createSslContext() {
|
|
// check keyfile
|
|
if (_httpsKeyfile.empty()) {
|
|
return true;
|
|
}
|
|
|
|
// validate protocol
|
|
if (_sslProtocol <= SSL_UNKNOWN || _sslProtocol >= SSL_LAST) {
|
|
LOG(ERR) << "invalid SSL protocol version specified. Please use a valid "
|
|
"value for --server.ssl-protocol.";
|
|
return false;
|
|
}
|
|
|
|
LOG(DEBUG) << "using SSL protocol version '"
|
|
<< protocolName((protocol_e)_sslProtocol) << "'";
|
|
|
|
if (!FileUtils::exists(_httpsKeyfile)) {
|
|
LOG(FATAL) << "unable to find SSL keyfile '" << _httpsKeyfile << "'";
|
|
FATAL_ERROR_EXIT();
|
|
}
|
|
|
|
// create context
|
|
_sslContext = sslContext(protocol_e(_sslProtocol), _httpsKeyfile);
|
|
|
|
if (_sslContext == nullptr) {
|
|
LOG(ERR) << "failed to create SSL context, cannot create HTTPS server";
|
|
return false;
|
|
}
|
|
|
|
// set cache mode
|
|
SSL_CTX_set_session_cache_mode(
|
|
_sslContext, _sslCache ? SSL_SESS_CACHE_SERVER : SSL_SESS_CACHE_OFF);
|
|
|
|
if (_sslCache) {
|
|
LOG(TRACE) << "using SSL session caching";
|
|
}
|
|
|
|
// set options
|
|
SSL_CTX_set_options(_sslContext, (long)_sslOptions);
|
|
|
|
std::string sslOptions = stringifySslOptions(_sslOptions);
|
|
LOG(INFO) << "using SSL options: " << sslOptions;
|
|
|
|
if (!_sslCipherList.empty()) {
|
|
if (SSL_CTX_set_cipher_list(_sslContext, _sslCipherList.c_str()) != 1) {
|
|
LOG(ERR) << "SSL error: " << lastSSLError();
|
|
LOG(FATAL) << "cannot set SSL cipher list '" << _sslCipherList << "'";
|
|
FATAL_ERROR_EXIT();
|
|
} else {
|
|
LOG(INFO) << "using SSL cipher-list '" << _sslCipherList << "'";
|
|
}
|
|
}
|
|
|
|
#if OPENSSL_VERSION_NUMBER >= 0x0090800fL
|
|
int sslEcdhNid;
|
|
EC_KEY *ecdhKey;
|
|
sslEcdhNid = OBJ_sn2nid(_sslEcdhCurve.c_str());
|
|
|
|
if (sslEcdhNid == 0) {
|
|
LOG(ERR) << "SSL error: " << lastSSLError() <<" Unknown curve name: " << _sslEcdhCurve;
|
|
FATAL_ERROR_EXIT();
|
|
}
|
|
|
|
// https://www.openssl.org/docs/manmaster/apps/ecparam.html
|
|
ecdhKey = EC_KEY_new_by_curve_name(sslEcdhNid);
|
|
if (ecdhKey == nullptr) {
|
|
LOG(ERR) << "SSL error: " << lastSSLError() <<" Unable to create curve by name: " << _sslEcdhCurve;
|
|
FATAL_ERROR_EXIT();
|
|
}
|
|
|
|
SSL_CTX_set_tmp_ecdh(_sslContext, ecdhKey);
|
|
SSL_CTX_set_options(_sslContext, SSL_OP_SINGLE_ECDH_USE);
|
|
EC_KEY_free(ecdhKey);
|
|
#endif
|
|
|
|
// set ssl context
|
|
Random::UniformCharacter r(
|
|
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789");
|
|
_rctx = r.random(SSL_MAX_SSL_SESSION_ID_LENGTH);
|
|
|
|
int res = SSL_CTX_set_session_id_context(
|
|
_sslContext, (unsigned char const*)_rctx.c_str(), (int)_rctx.size());
|
|
|
|
if (res != 1) {
|
|
LOG(ERR) << "SSL error: " << lastSSLError();
|
|
LOG(FATAL) << "cannot set SSL session id context '" << _rctx << "'";
|
|
FATAL_ERROR_EXIT();
|
|
}
|
|
|
|
// check CA
|
|
if (!_cafile.empty()) {
|
|
LOG(TRACE) << "trying to load CA certificates from '" << _cafile << "'";
|
|
|
|
int res = SSL_CTX_load_verify_locations(_sslContext, _cafile.c_str(), 0);
|
|
|
|
if (res == 0) {
|
|
LOG(ERR) << "SSL error: " << lastSSLError();
|
|
LOG(FATAL) << "cannot load CA certificates from '" << _cafile << "'";
|
|
FATAL_ERROR_EXIT();
|
|
}
|
|
|
|
STACK_OF(X509_NAME) * certNames;
|
|
|
|
certNames = SSL_load_client_CA_file(_cafile.c_str());
|
|
|
|
if (certNames == nullptr) {
|
|
LOG(ERR) << "ssl error: " << lastSSLError();
|
|
LOG(FATAL) << "cannot load CA certificates from '" << _cafile << "'";
|
|
FATAL_ERROR_EXIT();
|
|
}
|
|
|
|
if (Logger::logLevel() == arangodb::LogLevel::TRACE) {
|
|
for (int i = 0; i < sk_X509_NAME_num(certNames); ++i) {
|
|
X509_NAME* cert = sk_X509_NAME_value(certNames, i);
|
|
|
|
if (cert) {
|
|
BIOGuard bout(BIO_new(BIO_s_mem()));
|
|
|
|
X509_NAME_print_ex(bout._bio, cert, 0,
|
|
(XN_FLAG_SEP_COMMA_PLUS | XN_FLAG_DN_REV |
|
|
ASN1_STRFLGS_UTF8_CONVERT) &
|
|
~ASN1_STRFLGS_ESC_MSB);
|
|
|
|
char* r;
|
|
long len = BIO_get_mem_data(bout._bio, &r);
|
|
|
|
LOG(TRACE) << "name: " << std::string(r, len);
|
|
}
|
|
}
|
|
}
|
|
|
|
SSL_CTX_set_client_CA_list(_sslContext, certNames);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
std::string ApplicationEndpointServer::stringifySslOptions(uint64_t opts) const {
|
|
std::string result;
|
|
|
|
#ifdef SSL_OP_MICROSOFT_SESS_ID_BUG
|
|
if (opts & SSL_OP_MICROSOFT_SESS_ID_BUG) {
|
|
result.append(", SSL_OP_MICROSOFT_SESS_ID_BUG");
|
|
}
|
|
#endif
|
|
|
|
#ifdef SSL_OP_NETSCAPE_CHALLENGE_BUG
|
|
if (opts & SSL_OP_NETSCAPE_CHALLENGE_BUG) {
|
|
result.append(", SSL_OP_NETSCAPE_CHALLENGE_BUG");
|
|
}
|
|
#endif
|
|
|
|
#ifdef SSL_OP_LEGACY_SERVER_CONNECT
|
|
if (opts & SSL_OP_LEGACY_SERVER_CONNECT) {
|
|
result.append(", SSL_OP_LEGACY_SERVER_CONNECT");
|
|
}
|
|
#endif
|
|
|
|
#ifdef SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG
|
|
if (opts & SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG) {
|
|
result.append(", SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG");
|
|
}
|
|
#endif
|
|
|
|
#ifdef SSL_OP_TLSEXT_PADDING
|
|
if (opts & SSL_OP_TLSEXT_PADDING) {
|
|
result.append(", SSL_OP_TLSEXT_PADDING");
|
|
}
|
|
#endif
|
|
|
|
#ifdef SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER
|
|
if (opts & SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER) {
|
|
result.append(", SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER");
|
|
}
|
|
#endif
|
|
|
|
#ifdef SSL_OP_SAFARI_ECDHE_ECDSA_BUG
|
|
if (opts & SSL_OP_SAFARI_ECDHE_ECDSA_BUG) {
|
|
result.append(", SSL_OP_SAFARI_ECDHE_ECDSA_BUG");
|
|
}
|
|
#endif
|
|
|
|
#ifdef SSL_OP_SSLEAY_080_CLIENT_DH_BUG
|
|
if (opts & SSL_OP_SSLEAY_080_CLIENT_DH_BUG) {
|
|
result.append(", SSL_OP_SSLEAY_080_CLIENT_DH_BUG");
|
|
}
|
|
#endif
|
|
|
|
#ifdef SSL_OP_TLS_D5_BUG
|
|
if (opts & SSL_OP_TLS_D5_BUG) {
|
|
result.append(", SSL_OP_TLS_D5_BUG");
|
|
}
|
|
#endif
|
|
|
|
#ifdef SSL_OP_TLS_BLOCK_PADDING_BUG
|
|
if (opts & SSL_OP_TLS_BLOCK_PADDING_BUG) {
|
|
result.append(", SSL_OP_TLS_BLOCK_PADDING_BUG");
|
|
}
|
|
#endif
|
|
|
|
#ifdef SSL_OP_MSIE_SSLV2_RSA_PADDING
|
|
if (opts & SSL_OP_MSIE_SSLV2_RSA_PADDING) {
|
|
result.append(", SSL_OP_MSIE_SSLV2_RSA_PADDING");
|
|
}
|
|
#endif
|
|
|
|
#ifdef SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG
|
|
if (opts & SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG) {
|
|
result.append(", SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG");
|
|
}
|
|
#endif
|
|
|
|
#ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
|
|
if (opts & SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS) {
|
|
result.append(", SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS");
|
|
}
|
|
#endif
|
|
|
|
#ifdef SSL_OP_NO_QUERY_MTU
|
|
if (opts & SSL_OP_NO_QUERY_MTU) {
|
|
result.append(", SSL_OP_NO_QUERY_MTU");
|
|
}
|
|
#endif
|
|
|
|
#ifdef SSL_OP_COOKIE_EXCHANGE
|
|
if (opts & SSL_OP_COOKIE_EXCHANGE) {
|
|
result.append(", SSL_OP_COOKIE_EXCHANGE");
|
|
}
|
|
#endif
|
|
|
|
#ifdef SSL_OP_NO_TICKET
|
|
if (opts & SSL_OP_NO_TICKET) {
|
|
result.append(", SSL_OP_NO_TICKET");
|
|
}
|
|
#endif
|
|
|
|
#ifdef SSL_OP_CISCO_ANYCONNECT
|
|
if (opts & SSL_OP_CISCO_ANYCONNECT) {
|
|
result.append(", SSL_OP_CISCO_ANYCONNECT");
|
|
}
|
|
#endif
|
|
|
|
#ifdef SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION
|
|
if (opts & SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION) {
|
|
result.append(", SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION");
|
|
}
|
|
#endif
|
|
|
|
#ifdef SSL_OP_NO_COMPRESSION
|
|
if (opts & SSL_OP_NO_COMPRESSION) {
|
|
result.append(", SSL_OP_NO_COMPRESSION");
|
|
}
|
|
#endif
|
|
|
|
#ifdef SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION
|
|
if (opts & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION) {
|
|
result.append(", SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION");
|
|
}
|
|
#endif
|
|
|
|
#ifdef SSL_OP_SINGLE_ECDH_USE
|
|
if (opts & SSL_OP_SINGLE_ECDH_USE) {
|
|
result.append(", SSL_OP_SINGLE_ECDH_USE");
|
|
}
|
|
#endif
|
|
|
|
#ifdef SSL_OP_SINGLE_DH_USE
|
|
if (opts & SSL_OP_SINGLE_DH_USE) {
|
|
result.append(", SSL_OP_SINGLE_DH_USE");
|
|
}
|
|
#endif
|
|
|
|
#ifdef SSL_OP_EPHEMERAL_RSA
|
|
if (opts & SSL_OP_EPHEMERAL_RSA) {
|
|
result.append(", SSL_OP_EPHEMERAL_RSA");
|
|
}
|
|
#endif
|
|
|
|
#ifdef SSL_OP_CIPHER_SERVER_PREFERENCE
|
|
if (opts & SSL_OP_CIPHER_SERVER_PREFERENCE) {
|
|
result.append(", SSL_OP_CIPHER_SERVER_PREFERENCE");
|
|
}
|
|
#endif
|
|
|
|
#ifdef SSL_OP_TLS_ROLLBACK_BUG
|
|
if (opts & SSL_OP_TLS_ROLLBACK_BUG) {
|
|
result.append(", SSL_OP_TLS_ROLLBACK_BUG");
|
|
}
|
|
#endif
|
|
|
|
#ifdef SSL_OP_NO_SSLv2
|
|
if (opts & SSL_OP_NO_SSLv2) {
|
|
result.append(", SSL_OP_NO_SSLv2");
|
|
}
|
|
#endif
|
|
|
|
#ifdef SSL_OP_NO_SSLv3
|
|
if (opts & SSL_OP_NO_SSLv3) {
|
|
result.append(", SSL_OP_NO_SSLv3");
|
|
}
|
|
#endif
|
|
|
|
#ifdef SSL_OP_NO_TLSv1
|
|
if (opts & SSL_OP_NO_TLSv1) {
|
|
result.append(", SSL_OP_NO_TLSv1");
|
|
}
|
|
#endif
|
|
|
|
#ifdef SSL_OP_NO_TLSv1_2
|
|
if (opts & SSL_OP_NO_TLSv1_2) {
|
|
result.append(", SSL_OP_NO_TLSv1_2");
|
|
}
|
|
#endif
|
|
|
|
#ifdef SSL_OP_NO_TLSv1_1
|
|
if (opts & SSL_OP_NO_TLSv1_1) {
|
|
result.append(", SSL_OP_NO_TLSv1_1");
|
|
}
|
|
#endif
|
|
|
|
#ifdef SSL_OP_NO_DTLSv1
|
|
if (opts & SSL_OP_NO_DTLSv1) {
|
|
result.append(", SSL_OP_NO_DTLSv1");
|
|
}
|
|
#endif
|
|
|
|
#ifdef SSL_OP_NO_DTLSv1_2
|
|
if (opts & SSL_OP_NO_DTLSv1_2) {
|
|
result.append(", SSL_OP_NO_DTLSv1_2");
|
|
}
|
|
#endif
|
|
|
|
#ifdef SSL_OP_NO_SSL_MASK
|
|
if (opts & SSL_OP_NO_SSL_MASK) {
|
|
result.append(", SSL_OP_NO_SSL_MASK");
|
|
}
|
|
#endif
|
|
|
|
#ifdef SSL_OP_PKCS1_CHECK_1
|
|
if (opts & SSL_OP_PKCS1_CHECK_1) {
|
|
result.append(", SSL_OP_PKCS1_CHECK_1");
|
|
}
|
|
#endif
|
|
|
|
#ifdef SSL_OP_PKCS1_CHECK_2
|
|
if (opts & SSL_OP_PKCS1_CHECK_2) {
|
|
result.append(", SSL_OP_PKCS1_CHECK_2");
|
|
}
|
|
#endif
|
|
|
|
#ifdef SSL_OP_NETSCAPE_CA_DN_BUG
|
|
if (opts & SSL_OP_NETSCAPE_CA_DN_BUG) {
|
|
result.append(", SSL_OP_NETSCAPE_CA_DN_BUG");
|
|
}
|
|
#endif
|
|
|
|
#ifdef SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG
|
|
if (opts & SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG) {
|
|
result.append(", SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG");
|
|
}
|
|
#endif
|
|
|
|
#ifdef SSL_OP_CRYPTOPRO_TLSEXT_BUG
|
|
if (opts & SSL_OP_CRYPTOPRO_TLSEXT_BUG) {
|
|
result.append(", SSL_OP_CRYPTOPRO_TLSEXT_BUG");
|
|
}
|
|
#endif
|
|
|
|
if (result.empty()) {
|
|
return result;
|
|
}
|
|
|
|
// strip initial comma
|
|
return result.substr(2);
|
|
}
|
|
|