Skip to content

Commit

Permalink
CertificateSettings: Create basic Cert Store application
Browse files Browse the repository at this point in the history
This commit adds a new application named CertificateSettings that
houses our Cert Store. It should be expanded in the future.
  • Loading branch information
fdellwing authored and ADKaster committed Apr 4, 2023
1 parent 459dee1 commit c273784
Show file tree
Hide file tree
Showing 9 changed files with 237 additions and 0 deletions.
6 changes: 6 additions & 0 deletions Base/res/apps/CertificatesSettings.af
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[App]
Name=Certificate Settings
Executable=/bin/CertificateSettings
Category=Settings
Description=Access and change the system's certificates
ExcludeFromSystemMenu=true
Binary file added Base/res/icons/16x16/certificate.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Base/res/icons/32x32/certificate.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions Userland/Applications/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ add_subdirectory(BrowserSettings)
add_subdirectory(Calculator)
add_subdirectory(Calendar)
add_subdirectory(CalendarSettings)
add_subdirectory(CertificateSettings)
add_subdirectory(CharacterMap)
add_subdirectory(ClockSettings)
add_subdirectory(CrashReporter)
Expand Down
19 changes: 19 additions & 0 deletions Userland/Applications/CertificateSettings/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
serenity_component(
CertificateSettings
REQUIRED
TARGETS CertificateSettings
)

compile_gml(CertificateStore.gml CertificateStoreGML.h certificate_store_gml)

set(SOURCES
CertificateStore.cpp
main.cpp
)

set(GENERATED_SOURCES
CertificateStoreGML.h
)

serenity_app(CertificateSettings ICON certificate)
target_link_libraries(CertificateSettings PRIVATE LibCore LibCrypto LibGfx LibGUI LibMain LibTLS)
85 changes: 85 additions & 0 deletions Userland/Applications/CertificateSettings/CertificateStore.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*
* Copyright (c) 2023, Fabian Dellwing <[email protected]>
*
* SPDX-License-Identifier: BSD-2-Clause
*/

#include "CertificateStore.h"
#include <Applications/CertificateSettings/CertificateStoreGML.h>
#include <LibCrypto/ASN1/PEM.h>

namespace CertificateSettings {

NonnullRefPtr<CertificateStoreModel> CertificateStoreModel::create() { return adopt_ref(*new CertificateStoreModel); }

ErrorOr<void> CertificateStoreModel::load()
{
// FIXME: In the future, we will allow users to import their own certificates. To support this, we would need to change this logic
auto cacert_file = TRY(Core::File::open("/etc/cacert.pem"sv, Core::File::OpenMode::Read));
auto data = TRY(cacert_file->read_until_eof());
m_certificates = TRY(DefaultRootCACertificates::the().reload_certificates(data));

return {};
}

DeprecatedString CertificateStoreModel::column_name(int column) const
{
switch (column) {
case Column::IssuedTo:
return "Issued To";
case Column::IssuedBy:
return "Issued By";
case Column::Expire:
return "Expiration Date";
default:
VERIFY_NOT_REACHED();
}
}

GUI::Variant CertificateStoreModel::data(GUI::ModelIndex const& index, GUI::ModelRole role) const
{
if (role != GUI::ModelRole::Display)
return {};
if (m_certificates.is_empty())
return {};

auto cert = m_certificates.at(index.row());

switch (index.column()) {
case Column::IssuedTo:
return cert.subject.subject.is_empty() ? cert.subject.unit : cert.subject.subject;
case Column::IssuedBy:
return cert.issuer.subject.is_empty() ? cert.issuer.unit : cert.issuer.subject;
case Column::Expire:
return cert.not_after.to_deprecated_string("%Y-%m-%d"sv);
default:
VERIFY_NOT_REACHED();
}

return {};
}

ErrorOr<NonnullRefPtr<CertificateStoreWidget>> CertificateStoreWidget::try_create()
{
auto widget = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) CertificateStoreWidget()));
TRY(widget->initialize());
return widget;
}

ErrorOr<void> CertificateStoreWidget::initialize()
{
TRY(load_from_gml(certificate_store_gml));

m_root_ca_tableview = find_descendant_of_type_named<GUI::TableView>("root_ca_tableview");
m_root_ca_tableview->set_highlight_selected_rows(true);
m_root_ca_tableview->set_alternating_row_colors(false);

m_root_ca_model = CertificateStoreModel::create();
TRY(m_root_ca_model->load());
m_root_ca_tableview->set_model(m_root_ca_model);
m_root_ca_tableview->set_column_width(CertificateStoreModel::Column::IssuedTo, 150);
m_root_ca_tableview->set_column_width(CertificateStoreModel::Column::IssuedBy, 150);

return {};
}
}
40 changes: 40 additions & 0 deletions Userland/Applications/CertificateSettings/CertificateStore.gml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
@GUI::Widget {
fill_with_background_color: true
layout: @GUI::VerticalBoxLayout {
margins: [8]
}

@GUI::GroupBox {
title: "Trusted Root Certification Authorities"
fixed_height: 500
fixed_width: 465
layout: @GUI::VerticalBoxLayout {
margins: [8]
}

@GUI::TableView {
name: "root_ca_tableview"
}

@GUI::Widget {
layout: @GUI::HorizontalBoxLayout {
spacing: 6
}
preferred_height: "fit"

@GUI::Button {
name: "import_button"
text: "Import"
fixed_width: 80
enabled: false
}

@GUI::Button {
name: "export_button"
text: "Export"
fixed_width: 80
enabled: false
}
}
}
}
52 changes: 52 additions & 0 deletions Userland/Applications/CertificateSettings/CertificateStore.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* Copyright (c) 2023, Fabian Dellwing <[email protected]>
*
* SPDX-License-Identifier: BSD-2-Clause
*/

#pragma once

#include <LibGUI/Model.h>
#include <LibGUI/SettingsWindow.h>
#include <LibGUI/TableView.h>
#include <LibTLS/Certificate.h>

namespace CertificateSettings {

class CertificateStoreModel : public GUI::Model {
public:
enum Column {
IssuedTo,
IssuedBy,
Expire,
__Count
};

static NonnullRefPtr<CertificateStoreModel> create();
virtual ~CertificateStoreModel() override = default;

virtual int row_count(GUI::ModelIndex const& = GUI::ModelIndex()) const override { return m_certificates.size(); }
virtual int column_count(GUI::ModelIndex const& = GUI::ModelIndex()) const override { return Column::__Count; }
virtual DeprecatedString column_name(int) const override;
virtual GUI::Variant data(GUI::ModelIndex const&, GUI::ModelRole) const override;
virtual ErrorOr<void> load();

private:
Vector<Certificate> m_certificates;
};

class CertificateStoreWidget : public GUI::SettingsWindow::Tab {
C_OBJECT_ABSTRACT(CertStoreWidget)
public:
virtual ~CertificateStoreWidget() override = default;
static ErrorOr<NonnullRefPtr<CertificateStoreWidget>> try_create();
virtual void apply_settings() override {};

private:
CertificateStoreWidget() = default;
ErrorOr<void> initialize();

RefPtr<CertificateStoreModel> m_root_ca_model;
RefPtr<GUI::TableView> m_root_ca_tableview;
};
}
34 changes: 34 additions & 0 deletions Userland/Applications/CertificateSettings/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Copyright (c) 2023, Fabian Dellwing <[email protected]>
*
* SPDX-License-Identifier: BSD-2-Clause
*/

#include "CertificateStore.h"

#include <LibCore/System.h>
#include <LibGUI/Application.h>
#include <LibGUI/Icon.h>
#include <LibGUI/SettingsWindow.h>
#include <LibMain/Main.h>
#include <unistd.h>

ErrorOr<int> serenity_main(Main::Arguments args)
{
TRY(Core::System::pledge("stdio rpath wpath cpath recvfd sendfd unix"));

auto app = TRY(GUI::Application::try_create(args));

TRY(Core::System::unveil("/res", "r"));
TRY(Core::System::unveil("/etc/cacert.pem", "r"));
TRY(Core::System::unveil("/etc/timezone", "r"));
TRY(Core::System::unveil(nullptr, nullptr));

auto app_icon = GUI::Icon::default_icon("certificate"sv);
auto window = TRY(GUI::SettingsWindow::create("Certificates", GUI::SettingsWindow::ShowDefaultsButton::No));
auto cert_store_widget = TRY(window->add_tab<CertificateSettings::CertificateStoreWidget>(TRY("Certificate Store"_string), "certificate"sv));
window->set_icon(app_icon.bitmap_for_size(16));

window->show();
return app->exec();
}

0 comments on commit c273784

Please sign in to comment.