summaryrefslogtreecommitdiffstats
path: root/client
diff options
context:
space:
mode:
authorYonit Halperin <yhalperi@redhat.com>2010-03-18 10:21:47 +0100
committerAlexander Larsson <alexl@redhat.com>2010-03-18 10:21:47 +0100
commit457693fcfac7c178bdc9ca23295aa52d815ea0d6 (patch)
treef3176bcb321373b2f8974f6dcdeceb4082dba0cf /client
parentf16e16393e128a335b5e2d22c21315881409e99f (diff)
downloadspice-457693fcfac7c178bdc9ca23295aa52d815ea0d6.tar.gz
spice-457693fcfac7c178bdc9ca23295aa52d815ea0d6.tar.xz
spice-457693fcfac7c178bdc9ca23295aa52d815ea0d6.zip
client: add command line support for ciphers, ca file, and host certificate subject
Diffstat (limited to 'client')
-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 73a3461f..b9033997 100644
--- a/client/application.cpp
+++ b/client/application.cpp
@@ -321,6 +321,7 @@ enum AppCommands {
Application::Application()
: ProcessLoop (this)
, _client (*this)
+ , _con_ciphers ("DEFAULT")
, _enabled_channels (SPICE_END_CHANNEL, true)
, _main_screen (NULL)
, _active (false)
@@ -363,6 +364,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
@@ -1683,6 +1689,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;
@@ -1798,6 +1863,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,
@@ -1826,6 +1894,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');
@@ -1843,11 +1919,6 @@ bool Application::process_cmd_line(int argc, char** argv)
_peer_con_opt[i] = 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;
@@ -1894,6 +1965,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 b2a18d37..adf25175 100644
--- a/client/application.h
+++ b/client/application.h
@@ -188,6 +188,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;}
@@ -217,6 +218,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);
@@ -283,6 +287,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 e360d5f4..511c1cff 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().c_str(),
_client.get_password().c_str());
diff --git a/client/red_client.cpp b/client/red_client.cpp
index 40c77677..6a83a051 100644
--- a/client/red_client.cpp
+++ b/client/red_client.cpp
@@ -170,14 +170,15 @@ void Migrate::run()
DBG(0, "");
try {
conn_type = _client.get_connection_options(SPICE_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;
@@ -227,6 +228,7 @@ void Migrate::start(const SpiceMsgMainMigrationBegin* migrate)
migrate->pub_key_size);
}
+ _con_ciphers = _client.get_connection_ciphers();
_password = _client._password;
Lock lock(_lock);
_running = true;
@@ -460,6 +462,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 e62ed77b..5e783a5f 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;
@@ -155,6 +156,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, SpiceWaitForChannel* wait_list);
PixmapCache& get_pixmap_cache() {return _pixmap_cache;}
@@ -225,6 +227,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 5d939a4d..2f1ac194 100644
--- a/client/red_peer.cpp
+++ b/client/red_peer.cpp
@@ -466,7 +466,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;
@@ -515,6 +514,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 091f51aa..d31ba972 100644
--- a/client/red_peer.h
+++ b/client/red_peer.h
@@ -72,11 +72,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)
{
}
@@ -97,6 +99,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);