ability to connect to a host that require a PCKS certificate that is encrypted.
This commit is contained in:
parent
8d6172469c
commit
94644a2ee3
7 changed files with 106 additions and 39 deletions
|
@ -451,48 +451,70 @@
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">True</property>
|
<property name="can_focus">True</property>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkHBox" id="hbox2">
|
<object class="GtkVBox" id="vbox13">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
|
<property name="orientation">vertical</property>
|
||||||
<property name="spacing">6</property>
|
<property name="spacing">6</property>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkLabel" id="label28">
|
<object class="GtkHBox" id="hbox2">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="xalign">0</property>
|
<property name="spacing">6</property>
|
||||||
<property name="label" translatable="yes">_Client Cert File:</property>
|
<child>
|
||||||
<property name="use_underline">True</property>
|
<object class="GtkLabel" id="label28">
|
||||||
<property name="mnemonic_widget">cert_entry1</property>
|
<property name="visible">True</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
|
<property name="label" translatable="yes">_Client Cert File:</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="mnemonic_widget">cert_entry1</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkEntry" id="cert_entry1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="invisible_char">●</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="browse_for_client_cert_button">
|
||||||
|
<property name="label" translatable="yes">Browse...</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">True</property>
|
||||||
|
<signal name="clicked" handler="on_browse_for_client_cert_button_clicked"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
<property name="position">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="expand">False</property>
|
|
||||||
<property name="position">0</property>
|
<property name="position">0</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkEntry" id="cert_entry1">
|
<object class="GtkCheckButton" id="client_cert_encrypted_checkbutton1">
|
||||||
|
<property name="label" translatable="yes">Certificate is e_ncrypted</property>
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">True</property>
|
<property name="can_focus">True</property>
|
||||||
<property name="tooltip_text" translatable="yes">The path to the client certificate and key in PKCS#12 format</property>
|
<property name="receives_default">False</property>
|
||||||
<property name="invisible_char">●</property>
|
<property name="use_underline">True</property>
|
||||||
|
<property name="draw_indicator">True</property>
|
||||||
|
<signal name="toggled" handler="on_client_cert_encrypted_checkbutton1_toggled"/>
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="position">1</property>
|
<property name="position">1</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
|
||||||
<object class="GtkButton" id="browse_for_client_cert_button">
|
|
||||||
<property name="label" translatable="yes">Browse...</property>
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can_focus">True</property>
|
|
||||||
<property name="receives_default">True</property>
|
|
||||||
<property name="tooltip_text" translatable="yes">Choose Client Cert</property>
|
|
||||||
<signal name="clicked" handler="on_browse_for_client_cert_button_clicked"/>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">False</property>
|
|
||||||
<property name="fill">False</property>
|
|
||||||
<property name="position">2</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
<child type="label">
|
<child type="label">
|
||||||
|
|
|
@ -298,6 +298,7 @@ class Config:
|
||||||
'hostname': [ opt_str, '', '', True ],
|
'hostname': [ opt_str, '', '', True ],
|
||||||
'anonymous_auth': [ opt_bool, False ],
|
'anonymous_auth': [ opt_bool, False ],
|
||||||
'client_cert': [ opt_str, '', '', True ],
|
'client_cert': [ opt_str, '', '', True ],
|
||||||
|
'client_cert_encrypted': [ opt_bool, False, '', False ],
|
||||||
'savepass': [ opt_bool, False ],
|
'savepass': [ opt_bool, False ],
|
||||||
'password': [ opt_str, '' ],
|
'password': [ opt_str, '' ],
|
||||||
'resource': [ opt_str, 'gajim', '', True ],
|
'resource': [ opt_str, 'gajim', '', True ],
|
||||||
|
|
|
@ -749,6 +749,7 @@ class Connection(CommonConnection, ConnectionHandlers):
|
||||||
self.pingalives = 0
|
self.pingalives = 0
|
||||||
self.client_cert = gajim.config.get_per('accounts', self.name,
|
self.client_cert = gajim.config.get_per('accounts', self.name,
|
||||||
'client_cert')
|
'client_cert')
|
||||||
|
self.client_cert_passphrase = ''
|
||||||
|
|
||||||
def check_jid(self, jid):
|
def check_jid(self, jid):
|
||||||
return helpers.parse_jid(jid)
|
return helpers.parse_jid(jid)
|
||||||
|
@ -1155,29 +1156,42 @@ class Connection(CommonConnection, ConnectionHandlers):
|
||||||
secure_tuple = (self._current_type, cacerts, mycerts)
|
secure_tuple = (self._current_type, cacerts, mycerts)
|
||||||
|
|
||||||
con = common.xmpp.NonBlockingClient(
|
con = common.xmpp.NonBlockingClient(
|
||||||
domain=self._hostname,
|
domain=self._hostname,
|
||||||
caller=self,
|
caller=self,
|
||||||
idlequeue=gajim.idlequeue)
|
idlequeue=gajim.idlequeue)
|
||||||
|
|
||||||
self.last_connection = con
|
self.last_connection = con
|
||||||
# increase default timeout for server responses
|
# increase default timeout for server responses
|
||||||
common.xmpp.dispatcher_nb.DEFAULT_TIMEOUT_SECONDS = self.try_connecting_for_foo_secs
|
common.xmpp.dispatcher_nb.DEFAULT_TIMEOUT_SECONDS = \
|
||||||
|
self.try_connecting_for_foo_secs
|
||||||
# FIXME: this is a hack; need a better way
|
# FIXME: this is a hack; need a better way
|
||||||
if self.on_connect_success == self._on_new_account:
|
if self.on_connect_success == self._on_new_account:
|
||||||
con.RegisterDisconnectHandler(self._on_new_account)
|
con.RegisterDisconnectHandler(self._on_new_account)
|
||||||
|
|
||||||
self.log_hosttype_info(port)
|
if self.client_cert and gajim.config.get_per('accounts', self.name,
|
||||||
con.connect(
|
'client_cert_encrypted'):
|
||||||
hostname=self._current_host['host'],
|
gajim.nec.push_incoming_event(ClientCertPassphraseEvent(
|
||||||
port=port,
|
None, conn=self, con=con, port=port,
|
||||||
on_connect=self.on_connect_success,
|
secure_tuple=secure_tuple))
|
||||||
on_proxy_failure=self.on_proxy_failure,
|
return
|
||||||
on_connect_failure=self.connect_to_next_type,
|
self.on_client_cert_passphrase(None, con, port, secure_tuple)
|
||||||
proxy=self._proxy,
|
|
||||||
secure_tuple = secure_tuple)
|
|
||||||
else:
|
else:
|
||||||
self._connect_to_next_host(retry)
|
self._connect_to_next_host(retry)
|
||||||
|
|
||||||
|
def on_client_cert_passphrase(self, passphrase, con, port, secure_tuple):
|
||||||
|
self.client_cert_passphrase = passphrase
|
||||||
|
|
||||||
|
self.log_hosttype_info(port)
|
||||||
|
con.connect(
|
||||||
|
hostname=self._current_host['host'],
|
||||||
|
port=port,
|
||||||
|
on_connect=self.on_connect_success,
|
||||||
|
on_proxy_failure=self.on_proxy_failure,
|
||||||
|
on_connect_failure=self.connect_to_next_type,
|
||||||
|
proxy=self._proxy,
|
||||||
|
secure_tuple = secure_tuple)
|
||||||
|
|
||||||
def log_hosttype_info(self, port):
|
def log_hosttype_info(self, port):
|
||||||
msg = '>>>>>> Connecting to %s [%s:%d], type = %s' % (self.name,
|
msg = '>>>>>> Connecting to %s [%s:%d], type = %s' % (self.name,
|
||||||
self._current_host['host'], port, self._current_type)
|
self._current_host['host'], port, self._current_type)
|
||||||
|
|
|
@ -2069,3 +2069,7 @@ class MessageOutgoingEvent(nec.NetworkIncomingEvent):
|
||||||
|
|
||||||
def generate(self):
|
def generate(self):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
class ClientCertPassphraseEvent(nec.NetworkIncomingEvent):
|
||||||
|
name = 'client-cert-passphrase'
|
||||||
|
base_network_events = []
|
||||||
|
|
|
@ -359,7 +359,8 @@ class NonBlockingTLS(PlugIn):
|
||||||
tcpsock._sslContext = OpenSSL.SSL.Context(OpenSSL.SSL.TLSv1_METHOD)
|
tcpsock._sslContext = OpenSSL.SSL.Context(OpenSSL.SSL.TLSv1_METHOD)
|
||||||
log.debug('Using client cert and key from %s' % conn.client_cert)
|
log.debug('Using client cert and key from %s' % conn.client_cert)
|
||||||
try:
|
try:
|
||||||
p12 = OpenSSL.crypto.load_pkcs12(open(conn.client_cert).read())
|
p12 = OpenSSL.crypto.load_pkcs12(open(conn.client_cert).read(),
|
||||||
|
conn.client_cert_passphrase)
|
||||||
except OpenSSL.crypto.Error, exception_obj:
|
except OpenSSL.crypto.Error, exception_obj:
|
||||||
log.warning('Unable to load client pkcs12 certificate from '
|
log.warning('Unable to load client pkcs12 certificate from '
|
||||||
'file %s: %s ... Is it a valid PKCS12 cert?' % \
|
'file %s: %s ... Is it a valid PKCS12 cert?' % \
|
||||||
|
|
|
@ -1851,6 +1851,10 @@ class AccountsWindow:
|
||||||
|
|
||||||
client_cert = gajim.config.get_per('accounts', account, 'client_cert')
|
client_cert = gajim.config.get_per('accounts', account, 'client_cert')
|
||||||
self.xml.get_object('cert_entry1').set_text(client_cert)
|
self.xml.get_object('cert_entry1').set_text(client_cert)
|
||||||
|
client_cert_encrypted = gajim.config.get_per('accounts', account,
|
||||||
|
'client_cert_encrypted')
|
||||||
|
self.xml.get_object('client_cert_encrypted_checkbutton1').\
|
||||||
|
set_active(client_cert_encrypted)
|
||||||
|
|
||||||
self.xml.get_object('adjust_priority_with_status_checkbutton1').\
|
self.xml.get_object('adjust_priority_with_status_checkbutton1').\
|
||||||
set_active(gajim.config.get_per('accounts', account,
|
set_active(gajim.config.get_per('accounts', account,
|
||||||
|
@ -2222,6 +2226,12 @@ class AccountsWindow:
|
||||||
# if we showed ErrorDialog, there will not be dialog instance
|
# if we showed ErrorDialog, there will not be dialog instance
|
||||||
return
|
return
|
||||||
|
|
||||||
|
def on_client_cert_encrypted_checkbutton1_toggled(self, widget):
|
||||||
|
if self.ignore_events:
|
||||||
|
return
|
||||||
|
self.on_checkbutton_toggled(widget, 'client_cert_encrypted',
|
||||||
|
account=self.current_account)
|
||||||
|
|
||||||
def on_autoconnect_checkbutton_toggled(self, widget):
|
def on_autoconnect_checkbutton_toggled(self, widget):
|
||||||
if self.ignore_events:
|
if self.ignore_events:
|
||||||
return
|
return
|
||||||
|
|
|
@ -671,6 +671,19 @@ class Interface:
|
||||||
_('You are currently connected without your OpenPGP key.'))
|
_('You are currently connected without your OpenPGP key.'))
|
||||||
self.forget_gpg_passphrase(obj.keyID)
|
self.forget_gpg_passphrase(obj.keyID)
|
||||||
|
|
||||||
|
def handle_event_client_cert_passphrase(self, obj):
|
||||||
|
def on_ok(passphrase, checked):
|
||||||
|
obj.conn.on_client_cert_passphrase(passphrase, obj.con, obj.port,
|
||||||
|
obj.secure_tuple)
|
||||||
|
|
||||||
|
def on_cancel():
|
||||||
|
obj.conn.on_client_cert_passphrase('', obj.con, obj.port,
|
||||||
|
obj.secure_tuple)
|
||||||
|
|
||||||
|
dialogs.PassphraseDialog(_('Certificate Passphrase Required'),
|
||||||
|
_('Enter the passphrase for the certificate for account %s') % \
|
||||||
|
obj.conn.name, ok_handler=on_ok, cancel_handler=on_cancel)
|
||||||
|
|
||||||
def handle_event_gpg_password_required(self, obj):
|
def handle_event_gpg_password_required(self, obj):
|
||||||
#('GPG_PASSWORD_REQUIRED', account, (callback,))
|
#('GPG_PASSWORD_REQUIRED', account, (callback,))
|
||||||
if obj.keyid in self.gpg_passphrase:
|
if obj.keyid in self.gpg_passphrase:
|
||||||
|
@ -1401,6 +1414,8 @@ class Interface:
|
||||||
'atom-entry-received': [self.handle_atom_entry],
|
'atom-entry-received': [self.handle_atom_entry],
|
||||||
'bad-gpg-passphrase': [self.handle_event_bad_gpg_passphrase],
|
'bad-gpg-passphrase': [self.handle_event_bad_gpg_passphrase],
|
||||||
'bookmarks-received': [self.handle_event_bookmarks],
|
'bookmarks-received': [self.handle_event_bookmarks],
|
||||||
|
'client-cert-passphrase': [
|
||||||
|
self.handle_event_client_cert_passphrase],
|
||||||
'connection-lost': [self.handle_event_connection_lost],
|
'connection-lost': [self.handle_event_connection_lost],
|
||||||
'failed-decrypt': [(self.handle_event_failed_decrypt, ged.GUI2)],
|
'failed-decrypt': [(self.handle_event_failed_decrypt, ged.GUI2)],
|
||||||
'file-request-error': [self.handle_event_file_request_error],
|
'file-request-error': [self.handle_event_file_request_error],
|
||||||
|
|
Loading…
Add table
Reference in a new issue