diff --git a/src/common/config.py b/src/common/config.py index 167cc4377..e694754f3 100644 --- a/src/common/config.py +++ b/src/common/config.py @@ -354,6 +354,7 @@ class Config: 'warn_when_insecure_ssl_connection': [ opt_bool, True, _('Show a warning dialog before using standard SSL library.') ], 'warn_when_insecure_password': [ opt_bool, True, _('Show a warning dialog before sending PLAIN password over a plain connection.') ], 'ssl_fingerprint_sha1': [ opt_str, '', '', True ], + 'ssl_fingerprint_sha256': [ opt_str, '', '', True ], 'ignore_ssl_errors': [ opt_str, '', _('Space separated list of ssl errors to ignore.') ], 'use_srv': [ opt_bool, True, '', True ], 'use_custom_host': [ opt_bool, False, '', True ], diff --git a/src/common/connection.py b/src/common/connection.py index 948b821b9..24d95f629 100644 --- a/src/common/connection.py +++ b/src/common/connection.py @@ -1408,27 +1408,46 @@ class Connection(CommonConnection, ConnectionHandlers): text += _('\nSSL Error: %s') % ssl_error[errnum] else: text += _('\nUnknown SSL error: %d') % errnum - fingerprint = cert.digest('sha1').decode('utf-8') + fingerprint_sha1 = cert.digest('sha1').decode('utf-8') + fingerprint_sha256 = cert.digest('sha256').decode('utf-8') pem = OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_PEM, cert).decode('utf-8') gajim.nec.push_incoming_event(SSLErrorEvent(None, conn=self, error_text=text, error_num=errnum, cert=pem, - fingerprint=fingerprint, certificate=cert)) + fingerprint_sha1=fingerprint_sha1, + fingerprint_sha256=fingerprint_sha256, certificate=cert)) return True if cert: - fingerprint = cert.digest('sha1').decode('utf-8') - saved_fingerprint = gajim.config.get_per('accounts', self.name, + fingerprint_sha1 = cert.digest('sha1').decode('utf-8') + fingerprint_sha256 = cert.digest('sha256').decode('utf-8') + saved_fingerprint_sha1 = gajim.config.get_per('accounts', self.name, 'ssl_fingerprint_sha1') - if saved_fingerprint: + if saved_fingerprint_sha1: # Check sha1 fingerprint - if fingerprint != saved_fingerprint: + if fingerprint_sha1 != saved_fingerprint_sha1: gajim.nec.push_incoming_event(FingerprintErrorEvent(None, conn=self, certificate=cert, - new_fingerprint=fingerprint)) + new_fingerprint_sha1=fingerprint_sha1, + new_fingerprint_sha256=fingerprint_sha256)) return True else: gajim.config.set_per('accounts', self.name, - 'ssl_fingerprint_sha1', fingerprint) + 'ssl_fingerprint_sha1', fingerprint_sha1) + + saved_fingerprint_sha256 = gajim.config.get_per('accounts', self.name, + 'ssl_fingerprint_sha256') + if saved_fingerprint_sha256: + # Check sha256 fingerprint + if fingerprint_sha256 != saved_fingerprint_sha256: + gajim.nec.push_incoming_event(FingerprintErrorEvent(None, + conn=self, certificate=con.Connection.ssl_certificate, + new_fingerprint_sha1=fingerprint_sha1, + new_fingerprint_sha256=fingerprint_sha256)) + return True + else: + gajim.config.set_per('accounts', self.name, + 'ssl_fingerprint_sha256', fingerprint_sha256) + if not check_X509.check_certificate(cert, hostname) and \ '100' not in gajim.config.get_per('accounts', self.name, 'ignore_ssl_errors').split(): @@ -1439,7 +1458,8 @@ class Connection(CommonConnection, ConnectionHandlers): hostname gajim.nec.push_incoming_event(SSLErrorEvent(None, conn=self, error_text=txt, error_num=100, cert=pem, - fingerprint=fingerprint, certificate=cert)) + fingerprint_sha1=fingerprint_sha1, + fingerprint_sha256=fingerprint_sha256, certificate=cert)) return True self._register_handlers(con, con_type) diff --git a/src/common/connection_handlers_events.py b/src/common/connection_handlers_events.py index e5996f188..6c49ce733 100644 --- a/src/common/connection_handlers_events.py +++ b/src/common/connection_handlers_events.py @@ -1639,12 +1639,14 @@ class NewAccountConnectedEvent(nec.NetworkIncomingEvent): self.ssl_msg = ssl_error.get(er, _('Unknown SSL error: %d') % \ self.errnum) self.ssl_cert = '' - self.ssl_fingerprint = '' + self.ssl_fingerprint_sha1 = '' + self.ssl_fingerprint_sha256 = '' if self.conn.connection.Connection.ssl_certificate: cert = self.conn.connection.Connection.ssl_certificate self.ssl_cert = OpenSSL.crypto.dump_certificate( OpenSSL.crypto.FILETYPE_PEM, cert).decode('utf-8') - self.ssl_fingerprint = cert.digest('sha1').decode('utf-8') + self.ssl_fingerprint_sha1 = cert.digest('sha1').decode('utf-8') + self.ssl_fingerprint_sha256 = cert.digest('sha256').decode('utf-8') return True class NewAccountNotConnectedEvent(nec.NetworkIncomingEvent): diff --git a/src/config.py b/src/config.py index 9e3463dcf..b4f399274 100644 --- a/src/config.py +++ b/src/config.py @@ -3784,7 +3784,9 @@ class AccountCreationWizardWindow: f.write(self.ssl_cert + '\n\n') f.close() gajim.connections[self.account].new_account_info[ - 'ssl_fingerprint_sha1'] = self.ssl_fingerprint + 'ssl_fingerprint_sha1'] = self.ssl_fingerprint_sha1 + gajim.connections[self.account].new_account_info[ + 'ssl_fingerprint_sha256'] = self.ssl_fingerprint_sha256 self.notebook.set_current_page(4) # show fom page elif cur_page == 4: if self.is_form: @@ -3859,7 +3861,8 @@ class AccountCreationWizardWindow: self.forward_button.set_sensitive(False) self.notebook.set_current_page(4) # show form page return - self.ssl_fingerprint = obj.ssl_fingerprint + self.ssl_fingerprint_sha1 = obj.ssl_fingerprint_sha1 + self.ssl_fingerprint_sha256 = obj.ssl_fingerprint_sha256 self.ssl_cert = obj.ssl_cert if obj.ssl_msg: # An SSL warning occured, show it @@ -3873,8 +3876,9 @@ class AccountCreationWizardWindow: 'hostname': hostname, 'error': obj.ssl_msg}) if obj.errnum in (18, 27): text = _('Add this certificate to the list of trusted ' - 'certificates.\nSHA1 fingerprint of the certificate:\n%s') \ - % obj.ssl_fingerprint + 'certificates.\nSHA1 fingerprint of the certificate:\n%s' + '\nSHA256 fingerprint of the certificate:\n%s') \ + % (obj.ssl_fingerprint_sha1, obj.ssl_fingerprint_sha256) self.xml.get_object('ssl_checkbutton').set_label(text) else: self.xml.get_object('ssl_checkbutton').set_no_show_all(True) diff --git a/src/dialogs.py b/src/dialogs.py index c22109ac5..e02d651eb 100644 --- a/src/dialogs.py +++ b/src/dialogs.py @@ -5448,14 +5448,18 @@ Issued on: %(io)s Expires on: %(eo)s Fingerprint -SHA1 Fingerprint: %(sha1)s''') % { +SHA1 Fingerprint: %(sha1)s + +SHA256 Fingerprint: %(sha256)s +''') % { 'scn': subject.commonName, 'sorg': subject.organizationName, 'sou': subject.organizationalUnitName, 'sn': cert.get_serial_number(), 'icn': issuer.commonName, 'iorg': issuer.organizationName, 'iou': issuer.organizationalUnitName, 'io': cert.get_notBefore(), 'eo': cert.get_notAfter(), - 'sha1': cert.digest('sha1')}) + 'sha1': cert.digest('sha1'), + 'sha256': cert.digest('sha256')}) self.set_transient_for(parent) self.set_title(_('Certificate for account %s') % account) diff --git a/src/gui_interface.py b/src/gui_interface.py index 02f22718f..cb466a6ea 100644 --- a/src/gui_interface.py +++ b/src/gui_interface.py @@ -1300,7 +1300,7 @@ class Interface: obj.exchange_items_list, obj.fjid) def handle_event_ssl_error(self, obj): - # ('SSL_ERROR', account, (text, errnum, cert, sha1_fingerprint)) + # ('SSL_ERROR', account, (text, errnum, cert, sha1_fingerprint, sha256_fingerprint)) account = obj.conn.name server = gajim.config.get_per('accounts', account, 'hostname') @@ -1323,7 +1323,9 @@ class Interface: f.write(obj.cert + '\n\n') f.close() gajim.config.set_per('accounts', account, 'ssl_fingerprint_sha1', - obj.fingerprint) + obj.fingerprint_sha1) + gajim.config.set_per('accounts', account, 'ssl_fingerprint_sha256', + obj.fingerprint_sha256) if is_checked[1]: ignore_ssl_errors = gajim.config.get_per('accounts', account, 'ignore_ssl_errors').split() @@ -1344,8 +1346,9 @@ class Interface: 'server?') % {'error': obj.error_text} if obj.error_num in (18, 27): checktext1 = _('Add this certificate to the list of trusted ' - 'certificates.\nSHA1 fingerprint of the certificate:\n%s') % \ - obj.fingerprint + 'certificates.\nSHA1 fingerprint of the certificate:\n%s' + '\nSHA256 fingerprint of the certificate:\n%s') % \ + (obj.fingerprint_sha1, obj.fingerprint_sha256) else: checktext1 = '' checktext2 = _('Ignore this error for this certificate.') @@ -1359,12 +1362,14 @@ class Interface: _('SSL Certificate Verification for %s') % account) def handle_event_fingerprint_error(self, obj): - # ('FINGERPRINT_ERROR', account, (new_fingerprint,)) + # ('FINGERPRINT_ERROR', account, (new_fingerprint_sha1,new_fingerprint_sha256,)) account = obj.conn.name def on_yes(is_checked): del self.instances[account]['online_dialog']['fingerprint_error'] gajim.config.set_per('accounts', account, 'ssl_fingerprint_sha1', - obj.new_fingerprint) + obj.new_fingerprint_sha1) + gajim.config.set_per('accounts', account, 'ssl_fingerprint_sha256', + obj.new_fingerprint_sha256) # Reset the ignored ssl errors gajim.config.set_per('accounts', account, 'ignore_ssl_errors', '') obj.conn.ssl_certificate_accepted() @@ -1377,11 +1382,16 @@ class Interface: pritext = _('SSL certificate error') sectext = _('It seems the SSL certificate of account %(account)s has ' - 'changed or your connection is being hacked.\nOld fingerprint: ' - '%(old)s\nNew fingerprint: %(new)s\n\nDo you still want to connect ' + 'changed or your connection is being hacked.\n\nOld SHA-1 fingerprint: ' + '%(old_sha1)s\nOld SHA-256 fingerprint: %(old_sha256)s\n\n' + 'New SHA-1 fingerprint: %(new_sha1)s\nNew SHA-256 fingerprint: ' + '%(new_sha256)s\n\nDo you still want to connect ' 'and update the fingerprint of the certificate?') % \ - {'account': account, 'old': gajim.config.get_per('accounts', - account, 'ssl_fingerprint_sha1'), 'new': obj.new_fingerprint} + {'account': account, + 'old_sha1': gajim.config.get_per('accounts', account, 'ssl_fingerprint_sha1'), + 'old_sha256': gajim.config.get_per('accounts', account, 'ssl_fingerprint_sha256'), + 'new_sha1': obj.new_fingerprint_sha1, + 'new_sha256': obj.new_fingerprint_sha256} if 'fingerprint_error' in self.instances[account]['online_dialog']: self.instances[account]['online_dialog']['fingerprint_error'].\ destroy()