summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--client/application.cpp96
-rw-r--r--client/application.h5
-rw-r--r--client/red_channel.cpp3
-rw-r--r--client/red_client.cpp7
-rw-r--r--client/red_client.h3
-rw-r--r--client/red_peer.cpp7
-rw-r--r--client/red_peer.h5
7 files changed, 116 insertions, 10 deletions
diff --git a/client/application.cpp b/client/application.cpp
index 33cc947..8a010e4 100644
--- a/client/application.cpp
+++ b/client/application.cpp
@@ -265,6 +265,7 @@ enum AppCommands {
Application::Application()
: ProcessLoop (this)
, _client (*this)
+ , _con_ciphers ("DEFAULT")
, _enabled_channels (RED_CHANNEL_END, true)
, _main_screen (NULL)
, _active (false)
@@ -306,6 +307,11 @@ Application::Application()
_canvas_types[0] = CANVAS_OPTION_CAIRO;
#endif
+ _host_auth_opt.type_flags = RedPeer::HostAuthOptions::HOST_AUTH_OP_NAME;
+
+ Platform::get_app_data_dir(_host_auth_opt.CA_file, app_name);
+ Platform::path_append(_host_auth_opt.CA_file, CA_FILE_NAME);
+
std::auto_ptr<HotKeysParser> parser(new HotKeysParser("toggle-fullscreen=shift+f11"
",release-cursor=shift+f12"
#ifdef RED_DEBUG
@@ -1489,6 +1495,65 @@ bool Application::set_channels_security(CmdLineParser& parser, bool on, char *va
return true;
}
+bool Application::set_connection_ciphers(const char* ciphers, const char* arg0)
+{
+ _con_ciphers = ciphers;
+ return true;
+}
+
+bool Application::set_ca_file(const char* ca_file, const char* arg0)
+{
+ _host_auth_opt.CA_file = ca_file;
+ return true;
+}
+
+bool Application::set_host_cert_subject(const char* subject, const char* arg0)
+{
+ std::string subject_str(subject);
+ std::string::const_iterator iter = subject_str.begin();
+ std::string entry;
+ _host_auth_opt.type_flags = RedPeer::HostAuthOptions::HOST_AUTH_OP_SUBJECT;
+ _host_auth_opt.host_subject.clear();
+
+ while (true) {
+ if ((iter == subject_str.end()) || (*iter == ',')) {
+ RedPeer::HostAuthOptions::CertFieldValuePair entry_pair;
+ int value_pos = entry.find_first_of('=');
+ if ((value_pos == std::string::npos) || (value_pos == (entry.length() - 1))) {
+ Platform::term_printf("%s: host_subject bad format: assignment for %s is missing\n",
+ arg0, entry.c_str());
+ _exit_code = SPICEC_ERROR_CODE_INVALID_ARG;
+ return false;
+ }
+ entry_pair.first = entry.substr(0, value_pos);
+ entry_pair.second = entry.substr(value_pos + 1);
+ _host_auth_opt.host_subject.push_back(entry_pair);
+ DBG(0, "subject entry: %s=%s", entry_pair.first.c_str(), entry_pair.second.c_str());
+ if (iter == subject_str.end()) {
+ break;
+ }
+ entry.clear();
+ } else if (*iter == '\\') {
+ iter++;
+ if (iter == subject_str.end()) {
+ LOG_WARN("single \\ in host subject");
+ entry.append(1, '\\');
+ continue;
+ } else if ((*iter == '\\') || (*iter == ',')) {
+ entry.append(1, *iter);
+ } else {
+ LOG_WARN("single \\ in host subject");
+ entry.append(1, '\\');
+ continue;
+ }
+ } else {
+ entry.append(1, *iter);
+ }
+ iter++;
+ }
+ return true;
+}
+
bool Application::set_canvas_option(CmdLineParser& parser, char *val, const char* arg0)
{
typedef std::map< std::string, CanvasOption> CanvasNamesMap;
@@ -1577,6 +1642,9 @@ bool Application::process_cmd_line(int argc, char** argv)
SPICE_OPT_FULL_SCREEN,
SPICE_OPT_SECURE_CHANNELS,
SPICE_OPT_UNSECURE_CHANNELS,
+ SPICE_OPT_TLS_CIPHERS,
+ SPICE_OPT_CA_FILE,
+ SPICE_OPT_HOST_SUBJECT,
SPICE_OPT_ENABLE_CHANNELS,
SPICE_OPT_DISABLE_CHANNELS,
SPICE_OPT_CANVAS_TYPE,
@@ -1596,6 +1664,14 @@ bool Application::process_cmd_line(int argc, char** argv)
"force unsecure connection on the specified channels", "channel",
true);
parser.set_multi(SPICE_OPT_UNSECURE_CHANNELS, ',');
+ parser.add(SPICE_OPT_TLS_CIPHERS, "tls-ciphers", "ciphers for secure connections",
+ "ciphers", true);
+ parser.add(SPICE_OPT_CA_FILE, "ca-file", "truststore file for secure connections",
+ "ca-file", true);
+ parser.add(SPICE_OPT_HOST_SUBJECT, "host-subject",
+ "subject of the host certifcate. Format: field=value pairs separated"
+ " by commmas. Commas and backslashes within values must be preceded by"
+ " a backslash", "host-subject", true);
parser.add(SPICE_OPT_PASSWORD, "password", "server password", "password", true, 'w');
parser.add(SPICE_OPT_FULL_SCREEN, "full-screen", "open in full screen mode", "auto-conf",
false, 'f');
@@ -1616,11 +1692,6 @@ bool Application::process_cmd_line(int argc, char** argv)
_peer_con_opt[RED_CHANNEL_PLAYBACK] = RedPeer::ConnectionOptions::CON_OP_INVALID;
_peer_con_opt[RED_CHANNEL_RECORD] = RedPeer::ConnectionOptions::CON_OP_INVALID;
- _host_auth_opt.type_flags = RedPeer::HostAuthOptions::HOST_AUTH_OP_NAME;
-
- Platform::get_app_data_dir(_host_auth_opt.CA_file, app_name);
- Platform::path_append(_host_auth_opt.CA_file, CA_FILE_NAME);
-
parser.begin(argc, argv);
char* val;
@@ -1667,6 +1738,21 @@ bool Application::process_cmd_line(int argc, char** argv)
return false;
}
break;
+ case SPICE_OPT_TLS_CIPHERS:
+ if (!set_connection_ciphers(val, argv[0])) {
+ return false;
+ }
+ break;
+ case SPICE_OPT_CA_FILE:
+ if (!set_ca_file(val, argv[0])) {
+ return false;
+ }
+ break;
+ case SPICE_OPT_HOST_SUBJECT:
+ if (!set_host_cert_subject(val, argv[0])) {
+ return false;
+ }
+ break;
case SPICE_OPT_ENABLE_CHANNELS:
if (!set_enable_channels(parser, true, val, argv[0])) {
return false;
diff --git a/client/application.h b/client/application.h
index 27701eb..e924ce1 100644
--- a/client/application.h
+++ b/client/application.h
@@ -156,6 +156,7 @@ public:
void connect();
const PeerConnectionOptMap& get_con_opt_map() {return _peer_con_opt;}
const RedPeer::HostAuthOptions& get_host_auth_opt() { return _host_auth_opt;}
+ const std::string& get_connection_ciphers() { return _con_ciphers;}
uint32_t get_mouse_mode();
const std::vector<int>& get_canvas_types() { return _canvas_types;}
@@ -166,6 +167,9 @@ public:
private:
bool set_channels_security(CmdLineParser& parser, bool on, char *val, const char* arg0);
+ bool set_connection_ciphers(const char* ciphers, const char* arg0);
+ bool set_ca_file(const char* ca_file, const char* arg0);
+ bool set_host_cert_subject(const char* subject, const char* arg0);
bool set_enable_channels(CmdLineParser& parser, bool enable, char *val, const char* arg0);
bool set_canvas_option(CmdLineParser& parser, char *val, const char* arg0);
void on_cmd_line_invalid_arg(const char* arg0, const char* what, const char* val);
@@ -226,6 +230,7 @@ private:
RedClient _client;
PeerConnectionOptMap _peer_con_opt;
RedPeer::HostAuthOptions _host_auth_opt;
+ std::string _con_ciphers;
std::vector<bool> _enabled_channels;
std::vector<RedScreen*> _screens;
RedScreen* _main_screen;
diff --git a/client/red_channel.cpp b/client/red_channel.cpp
index 153055d..048cef2 100644
--- a/client/red_channel.cpp
+++ b/client/red_channel.cpp
@@ -396,7 +396,8 @@ void RedChannel::run()
ConnectionOptions con_options(_client.get_connection_options(get_type()),
_client.get_port(),
_client.get_sport(),
- _client.get_host_auth_options());
+ _client.get_host_auth_options(),
+ _client.get_connection_ciphers());
RedChannelBase::connect(con_options, _client.get_connection_id(),
_client.get_host(), _client.get_password());
on_connect();
diff --git a/client/red_client.cpp b/client/red_client.cpp
index df88e7a..9079326 100644
--- a/client/red_client.cpp
+++ b/client/red_client.cpp
@@ -129,14 +129,15 @@ void Migrate::run()
DBG(0, "");
try {
conn_type = _client.get_connection_options(RED_CHANNEL_MAIN);
- RedPeer::ConnectionOptions con_opt(conn_type, _port, _sport, _auth_options);
+ RedPeer::ConnectionOptions con_opt(conn_type, _port, _sport, _auth_options, _con_ciphers);
MigChannels::iterator iter = _channels.begin();
connection_id = _client.get_connection_id();
connect_one(**iter, con_opt, connection_id);
for (++iter; iter != _channels.end(); ++iter) {
conn_type = _client.get_connection_options((*iter)->get_type());
- con_opt = RedPeer::ConnectionOptions(conn_type, _port, _sport, _auth_options);
+ con_opt = RedPeer::ConnectionOptions(conn_type, _port, _sport,
+ _auth_options, _con_ciphers);
connect_one(**iter, con_opt, connection_id);
}
_connected = true;
@@ -186,6 +187,7 @@ void Migrate::start(const RedMigrationBegin* migrate)
migrate->pub_key_size);
}
+ _con_ciphers = _client.get_connection_ciphers();
_password = _client._password;
Lock lock(_lock);
_running = true;
@@ -410,6 +412,7 @@ void RedClient::connect()
}
_host_auth_opt = _application.get_host_auth_opt();
+ _con_ciphers = _application.get_connection_ciphers();
RedChannel::connect();
}
diff --git a/client/red_client.h b/client/red_client.h
index d97128e..b7edadb 100644
--- a/client/red_client.h
+++ b/client/red_client.h
@@ -77,6 +77,7 @@ private:
int _port;
int _sport;
RedPeer::HostAuthOptions _auth_options;
+ std::string _con_ciphers;
Thread* _thread;
Mutex _lock;
Condition _cond;
@@ -150,6 +151,7 @@ public:
bool is_auto_display_res() { return _auto_display_res;}
RedPeer::ConnectionOptions::Type get_connection_options(uint32_t channel_type);
RedPeer::HostAuthOptions& get_host_auth_options() { return _host_auth_opt;}
+ const std::string& get_connection_ciphers() { return _con_ciphers;}
void get_sync_info(uint8_t channel_type, uint8_t channel_id, SyncInfo& info);
void wait_for_channels(int wait_list_size, RedWaitForChannel* wait_list);
PixmapCache& get_pixmap_cache() {return _pixmap_cache;}
@@ -218,6 +220,7 @@ private:
PeerConnectionOptMap _con_opt_map;
RedPeer::HostAuthOptions _host_auth_opt;
+ std::string _con_ciphers;
Migrate _migrate;
Mutex _channels_lock;
typedef std::list<ChannelFactory*> Factorys;
diff --git a/client/red_peer.cpp b/client/red_peer.cpp
index a1dca53..069fdae 100644
--- a/client/red_peer.cpp
+++ b/client/red_peer.cpp
@@ -509,7 +509,6 @@ int RedPeer::ssl_verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
return 0;
}
-// todo: use SSL_CTX_set_cipher_list, etc.
void RedPeer::connect_secure(const ConnectionOptions& options, const char* host)
{
int return_code;
@@ -558,6 +557,12 @@ void RedPeer::connect_secure(const ConnectionOptions& options, const char* host)
SSL_CTX_set_verify(_ctx, SSL_VERIFY_PEER, ssl_verify_callback);
}
+ return_code = SSL_CTX_set_cipher_list(_ctx, options.ciphers.c_str());
+ if (return_code != 1) {
+ LOG_WARN("SSL_CTX_set_cipher_list failed, ciphers=%s", options.ciphers.c_str());
+ ssl_error();
+ }
+
_ssl = SSL_new(_ctx);
if (!_ssl) {
THROW("create ssl failed");
diff --git a/client/red_peer.h b/client/red_peer.h
index 761aed1..6a80f8c 100644
--- a/client/red_peer.h
+++ b/client/red_peer.h
@@ -77,11 +77,13 @@ public:
};
ConnectionOptions(Type in_type, int in_port, int in_sport,
- const HostAuthOptions& in_host_auth)
+ const HostAuthOptions& in_host_auth,
+ const std::string& in_ciphers)
: type (in_type)
, unsecure_port (in_port)
, secure_port (in_sport)
, host_auth (in_host_auth)
+ , ciphers (in_ciphers)
{
}
@@ -102,6 +104,7 @@ public:
int unsecure_port;
int secure_port;
HostAuthOptions host_auth; // for secure connection
+ std::string ciphers;
};
void connect_unsecure(const char* host, int port);