diff options
author | wurstsalat <mailtrash@posteo.de> | 2022-11-11 20:59:42 +0300 |
---|---|---|
committer | Philipp Hörist <philipp@hoerist.com> | 2022-11-27 22:35:20 +0300 |
commit | 8da84be4c16bf26c34fa48dc22e520b684895ab4 (patch) | |
tree | b18330d63ef0e05449a5bcbc79fb0005dc3a2a9b | |
parent | bd8b229b474adb038903b65a373c910845af3062 (diff) |
refactor: CertificateBox: Use cryptography module for certificate details
-rw-r--r-- | gajim/common/helpers.py | 12 | ||||
-rw-r--r-- | gajim/gtk/certificate_dialog.py | 74 | ||||
-rw-r--r-- | test/gtk/certificate_dialog.py | 12 | ||||
-rw-r--r-- | test/gtk/util.py | 11 |
4 files changed, 62 insertions, 47 deletions
diff --git a/gajim/common/helpers.py b/gajim/common/helpers.py index 575814d96..30b4cb8f7 100644 --- a/gajim/common/helpers.py +++ b/gajim/common/helpers.py @@ -62,6 +62,9 @@ from pathlib import Path from packaging.version import Version as V import unicodedata +from cryptography import x509 +from cryptography.hazmat.backends import default_backend + from nbxmpp.namespaces import Namespace from nbxmpp.const import Role from nbxmpp.const import Chatstate @@ -75,9 +78,6 @@ from nbxmpp.protocol import JID from nbxmpp.protocol import InvalidJid from nbxmpp.protocol import Iq -from OpenSSL.crypto import X509, load_certificate -from OpenSSL.crypto import FILETYPE_PEM - from gi.repository import Gio from gi.repository import GLib from gi.repository import GObject @@ -1429,8 +1429,10 @@ def load_file_async(path: Path, file.load_contents_async(None, _on_load_finished) -def convert_gio_to_openssl_cert(cert: Gio.TlsCertificate) -> X509: - return load_certificate(FILETYPE_PEM, cert.props.certificate_pem.encode()) +def get_x509_cert_from_gio_cert(cert: Gio.TlsCertificate) -> x509.Certificate: + glib_bytes = GLib.ByteArray.free_to_bytes(cert.props.certificate) + return x509.load_der_x509_certificate( + glib_bytes.get_data(), default_backend()) def get_custom_host(account: str) -> Optional[tuple[str, diff --git a/gajim/gtk/certificate_dialog.py b/gajim/gtk/certificate_dialog.py index 1a1469caf..0c2ca8f87 100644 --- a/gajim/gtk/certificate_dialog.py +++ b/gajim/gtk/certificate_dialog.py @@ -12,14 +12,14 @@ # You should have received a copy of the GNU General Public License # along with Gajim. If not, see <http://www.gnu.org/licenses/>. -from datetime import datetime +from cryptography.hazmat.primitives import hashes from gi.repository import Gdk from gi.repository import Gio from gi.repository import Gtk from gajim.common import app -from gajim.common.helpers import convert_gio_to_openssl_cert +from gajim.common.helpers import get_x509_cert_from_gio_cert from gajim.common.i18n import _ from .builder import get_builder @@ -55,47 +55,55 @@ class CertificateDialog(Gtk.ApplicationWindow): class CertificateBox(Gtk.Box): - def __init__(self, account: str, cert: Gio.TlsCertificate) -> None: + def __init__(self, account: str, certificate: Gio.TlsCertificate) -> None: Gtk.Box.__init__(self) self._ui = get_builder('certificate.ui') - - certificate = convert_gio_to_openssl_cert(cert) - - issuer = certificate.get_issuer() - subject = certificate.get_subject() - self._headline = _('Certificate for \n%s') % account - self._it_common_name = subject.commonName or '' - self._it_organization = subject.organizationName or '' - self._it_org_unit = subject.organizationalUnitName or '' - it_serial_no = str(certificate.get_serial_number()) + + cert = get_x509_cert_from_gio_cert(certificate) + + self._it_common_name = '' + self._it_organization = '' + self._it_org_unit = '' + for attribute in cert.subject: + # See https://datatracker.ietf.org/doc/html/rfc4514.html + dotted_string = attribute.oid.dotted_string + if dotted_string == '2.5.4.3': + self._ib_common_name = str(attribute.value) + if dotted_string == '2.5.4.10': + self._ib_organization = str(attribute.value) + if dotted_string == '2.5.4.11': + self._ib_org_unit = str(attribute.value) + + it_serial_no = str(cert.serial_number) it_serial_no_half = int(len(it_serial_no) / 2) self._it_serial_number = '%s\n%s' % ( it_serial_no[:it_serial_no_half], it_serial_no[it_serial_no_half:]) - self._ib_common_name = issuer.commonName or '' - self._ib_organization = issuer.organizationName or '' - self._ib_org_unit = issuer.organizationalUnitName or '' - - before = certificate.get_notBefore() - if before is None: - self._issued = '' - else: - issued = datetime.strptime(before.decode('ascii'), '%Y%m%d%H%M%SZ') - self._issued = issued.strftime('%c %Z') - - after = certificate.get_notAfter() - if after is None: - self._expires = '' - else: - expires = datetime.strptime(after.decode('ascii'), '%Y%m%d%H%M%SZ') - self._expires = expires.strftime('%c %Z') - - sha1 = certificate.digest('sha1').decode('utf-8') + + self._ib_common_name = '' + self._ib_organization = '' + self._ib_org_unit = '' + for attribute in cert.issuer: + # See https://datatracker.ietf.org/doc/html/rfc4514.html + dotted_string = attribute.oid.dotted_string + if dotted_string == '2.5.4.3': + self._ib_common_name = str(attribute.value) + if dotted_string == '2.5.4.10': + self._ib_organization = str(attribute.value) + if dotted_string == '2.5.4.11': + self._ib_org_unit = str(attribute.value) + + self._issued = cert.not_valid_before.strftime('%c %Z') + self._expires = cert.not_valid_after.strftime('%c %Z') + + sha1_bytes = cert.fingerprint(hashes.SHA1()) + sha1 = ':'.join(f'{b:02X}' for b in sha1_bytes) self._sha1 = '%s\n%s' % (sha1[:29], sha1[30:]) - sha256 = certificate.digest('sha256').decode('utf-8') + sha256_bytes = cert.fingerprint(hashes.SHA256()) + sha256 = ':'.join(f'{b:02X}' for b in sha256_bytes) self._sha256 = '%s\n%s\n%s\n%s' % ( sha256[:23], sha256[24:47], sha256[48:71], sha256[72:]) diff --git a/test/gtk/certificate_dialog.py b/test/gtk/certificate_dialog.py index 534fe5500..48faa7cd7 100644 --- a/test/gtk/certificate_dialog.py +++ b/test/gtk/certificate_dialog.py @@ -1,15 +1,15 @@ import gi +gi.require_version('Gio', '2.0') gi.require_version('Gtk', '3.0') +from gi.repository import Gio from gi.repository import Gtk -import OpenSSL - from gajim import gui gui.init('gtk') from test.gtk import util from gajim.common.const import CSSPriority -from gajim.gui.dialogs import CertificateDialog +from gajim.gui.certificate_dialog import CertificateDialog util.load_style('gajim.css', CSSPriority.APPLICATION) @@ -47,8 +47,8 @@ ejsJoYkpvcaiaLAyVymTY/n/oM2oQpv5Mqjit+18RB9c2P+ifH5iDKC/jTKn4NNz 8xSTlUlCBTCozjzscZVeVDIojmejWclT -----END CERTIFICATE-----''' -cert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, cert) -win = CertificateDialog(None, 'testacc', cert) -win.connect("destroy", Gtk.main_quit) +gio_cert = Gio.TlsCertificate.new_from_pem(cert, -1) +win = CertificateDialog(None, 'testacc', gio_cert) +win.connect('destroy', Gtk.main_quit) win.show_all() Gtk.main() diff --git a/test/gtk/util.py b/test/gtk/util.py index 9ecd50ece..06a949c5e 100644 --- a/test/gtk/util.py +++ b/test/gtk/util.py @@ -3,12 +3,15 @@ from pathlib import Path from gi.repository import Gdk from gi.repository import Gtk +from gajim.common.const import CSSPriority -def get_gajim_dir(): + +def get_gajim_dir() -> Path: gajim_path = Path(__file__) / '..' / '..' / '..' / 'gajim' return gajim_path.resolve() -def load_style(filename, priority): + +def load_style(filename: str, priority: CSSPriority) -> None: path = get_gajim_dir() / 'data' / 'style' / filename try: with open(str(path), 'r', encoding='utf8') as file: @@ -18,6 +21,8 @@ def load_style(filename, priority): return provider = Gtk.CssProvider() provider.load_from_data(bytes(css.encode('utf-8'))) - Gtk.StyleContext.add_provider_for_screen(Gdk.Screen.get_default(), + screen = Gdk.Screen.get_default() + assert screen is not None + Gtk.StyleContext.add_provider_for_screen(screen, provider, priority) |