Selaa lähdekoodia

RequestServer+LibTLS: Allow applications to specify multiple root certs

Andrew Kaster 1 vuosi sitten
vanhempi
commit
080aa567a5

+ 4 - 4
Ladybird/Android/src/main/cpp/RequestServerService.cpp

@@ -21,13 +21,13 @@
 #include <RequestServer/HttpsProtocol.h>
 
 // FIXME: Share b/w RequestServer and WebSocket
-ErrorOr<String> find_certificates(StringView serenity_resource_root)
+ErrorOr<ByteString> find_certificates(StringView serenity_resource_root)
 {
-    auto cert_path = TRY(String::formatted("{}/res/ladybird/cacert.pem", serenity_resource_root));
+    auto cert_path = ByteString::formatted("{}/res/ladybird/cacert.pem", serenity_resource_root);
     if (!FileSystem::exists(cert_path)) {
         auto app_dir = LexicalPath::dirname(TRY(Core::System::current_executable_path()));
 
-        cert_path = TRY(String::formatted("{}/cacert.pem", LexicalPath(app_dir).parent()));
+        cert_path = ByteString::formatted("{}/cacert.pem", LexicalPath(app_dir).parent());
         if (!FileSystem::exists(cert_path))
             return Error::from_string_view("Don't know how to load certs!"sv);
     }
@@ -37,7 +37,7 @@ ErrorOr<String> find_certificates(StringView serenity_resource_root)
 ErrorOr<int> service_main(int ipc_socket, int fd_passing_socket)
 {
     // Ensure the certificates are read out here.
-    DefaultRootCACertificates::set_default_certificate_path(TRY(find_certificates(s_serenity_resource_root)));
+    DefaultRootCACertificates::set_default_certificate_paths(Vector { TRY(find_certificates(s_serenity_resource_root)) });
     [[maybe_unused]] auto& certs = DefaultRootCACertificates::the();
 
     Core::EventLoop event_loop;

+ 4 - 4
Ladybird/Android/src/main/cpp/WebSocketService.cpp

@@ -17,13 +17,13 @@
 #include <WebSocket/ConnectionFromClient.h>
 
 // FIXME: Share b/w RequestServer and WebSocket
-ErrorOr<String> find_certificates(StringView serenity_resource_root)
+ErrorOr<ByteString> find_certificates(StringView serenity_resource_root)
 {
-    auto cert_path = TRY(String::formatted("{}/res/ladybird/cacert.pem", serenity_resource_root));
+    auto cert_path = ByteString::formatted("{}/res/ladybird/cacert.pem", serenity_resource_root);
     if (!FileSystem::exists(cert_path)) {
         auto app_dir = LexicalPath::dirname(TRY(Core::System::current_executable_path()));
 
-        cert_path = TRY(String::formatted("{}/cacert.pem", LexicalPath(app_dir).parent()));
+        cert_path = ByteString::formatted("{}/cacert.pem", LexicalPath(app_dir).parent());
         if (!FileSystem::exists(cert_path))
             return Error::from_string_view("Don't know how to load certs!"sv);
     }
@@ -33,7 +33,7 @@ ErrorOr<String> find_certificates(StringView serenity_resource_root)
 ErrorOr<int> service_main(int ipc_socket, int fd_passing_socket)
 {
     // Ensure the certificates are read out here.
-    DefaultRootCACertificates::set_default_certificate_path(TRY(find_certificates(s_serenity_resource_root)));
+    DefaultRootCACertificates::set_default_certificate_paths(Vector { TRY(find_certificates(s_serenity_resource_root)) });
     [[maybe_unused]] auto& certs = DefaultRootCACertificates::the();
 
     Core::EventLoop event_loop;

+ 8 - 4
Ladybird/RequestServer/main.cpp

@@ -21,13 +21,13 @@
 #include <RequestServer/HttpsProtocol.h>
 
 // FIXME: Share b/w RequestServer and WebSocket
-ErrorOr<String> find_certificates(StringView serenity_resource_root)
+ErrorOr<ByteString> find_certificates(StringView serenity_resource_root)
 {
-    auto cert_path = TRY(String::formatted("{}/res/ladybird/cacert.pem", serenity_resource_root));
+    auto cert_path = ByteString::formatted("{}/res/ladybird/cacert.pem", serenity_resource_root);
     if (!FileSystem::exists(cert_path)) {
         auto app_dir = LexicalPath::dirname(TRY(Core::System::current_executable_path()));
 
-        cert_path = TRY(String::formatted("{}/cacert.pem", LexicalPath(app_dir).parent()));
+        cert_path = ByteString::formatted("{}/cacert.pem", LexicalPath(app_dir).parent());
         if (!FileSystem::exists(cert_path))
             return Error::from_string_view("Don't know how to load certs!"sv);
     }
@@ -40,14 +40,18 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
 
     int fd_passing_socket { -1 };
     StringView serenity_resource_root;
+    Vector<ByteString> certificates;
 
     Core::ArgsParser args_parser;
     args_parser.add_option(fd_passing_socket, "File descriptor of the fd passing socket", "fd-passing-socket", 'c', "fd-passing-socket");
+    args_parser.add_option(certificates, "Path to a certificate file", "certificate", 'C', "certificate");
     args_parser.add_option(serenity_resource_root, "Absolute path to directory for serenity resources", "serenity-resource-root", 'r', "serenity-resource-root");
     args_parser.parse(arguments);
 
     // Ensure the certificates are read out here.
-    DefaultRootCACertificates::set_default_certificate_path(TRY(find_certificates(serenity_resource_root)));
+    if (certificates.is_empty())
+        certificates.append(TRY(find_certificates(serenity_resource_root)));
+    DefaultRootCACertificates::set_default_certificate_paths(certificates.span());
     [[maybe_unused]] auto& certs = DefaultRootCACertificates::the();
 
     Core::EventLoop event_loop;

+ 8 - 4
Ladybird/WebSocket/main.cpp

@@ -17,13 +17,13 @@
 #include <WebSocket/ConnectionFromClient.h>
 
 // FIXME: Share b/w RequestServer and WebSocket
-ErrorOr<String> find_certificates(StringView serenity_resource_root)
+ErrorOr<ByteString> find_certificates(StringView serenity_resource_root)
 {
-    auto cert_path = TRY(String::formatted("{}/res/ladybird/cacert.pem", serenity_resource_root));
+    auto cert_path = ByteString::formatted("{}/res/ladybird/cacert.pem", serenity_resource_root);
     if (!FileSystem::exists(cert_path)) {
         auto app_dir = LexicalPath::dirname(TRY(Core::System::current_executable_path()));
 
-        cert_path = TRY(String::formatted("{}/cacert.pem", LexicalPath(app_dir).parent()));
+        cert_path = ByteString::formatted("{}/cacert.pem", LexicalPath(app_dir).parent());
         if (!FileSystem::exists(cert_path))
             return Error::from_string_view("Don't know how to load certs!"sv);
     }
@@ -36,14 +36,18 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
 
     int fd_passing_socket { -1 };
     StringView serenity_resource_root;
+    Vector<ByteString> certificates;
 
     Core::ArgsParser args_parser;
     args_parser.add_option(fd_passing_socket, "File descriptor of the fd passing socket", "fd-passing-socket", 'c', "fd-passing-socket");
+    args_parser.add_option(certificates, "Path to a certificate file", "certificate", 'C', "certificate");
     args_parser.add_option(serenity_resource_root, "Absolute path to directory for serenity resources", "serenity-resource-root", 'r', "serenity-resource-root");
     args_parser.parse(arguments);
 
     // Ensure the certificates are read out here.
-    DefaultRootCACertificates::set_default_certificate_path(TRY(find_certificates(serenity_resource_root)));
+    if (certificates.is_empty())
+        certificates.append(TRY(find_certificates(serenity_resource_root)));
+    DefaultRootCACertificates::set_default_certificate_paths(certificates.span());
     [[maybe_unused]] auto& certs = DefaultRootCACertificates::the();
 
     Core::EventLoop event_loop;

+ 2 - 2
Userland/Libraries/LibTLS/Certificate.h

@@ -292,11 +292,11 @@ public:
     Vector<Certificate> const& certificates() const { return m_ca_certificates; }
 
     static ErrorOr<Vector<Certificate>> parse_pem_root_certificate_authorities(ByteBuffer&);
-    static ErrorOr<Vector<Certificate>> load_certificates(StringView custom_cert_path = {});
+    static ErrorOr<Vector<Certificate>> load_certificates(Span<ByteString> custom_cert_paths = {});
 
     static DefaultRootCACertificates& the();
 
-    static void set_default_certificate_path(String);
+    static void set_default_certificate_paths(Span<ByteString> paths);
 
 private:
     Vector<Certificate> m_ca_certificates;

+ 13 - 8
Userland/Libraries/LibTLS/TLSv12.cpp

@@ -547,16 +547,19 @@ Vector<Certificate> TLSv12::parse_pem_certificate(ReadonlyBytes certificate_pem_
     return { move(certificate) };
 }
 
-static String s_default_ca_certificate_path;
+static Vector<ByteString> s_default_ca_certificate_paths;
 
-void DefaultRootCACertificates::set_default_certificate_path(String path)
+void DefaultRootCACertificates::set_default_certificate_paths(Span<ByteString> paths)
 {
-    s_default_ca_certificate_path = move(path);
+    s_default_ca_certificate_paths.clear();
+    s_default_ca_certificate_paths.ensure_capacity(paths.size());
+    for (auto& path : paths)
+        s_default_ca_certificate_paths.unchecked_append(path);
 }
 
 DefaultRootCACertificates::DefaultRootCACertificates()
 {
-    auto load_result = load_certificates(s_default_ca_certificate_path);
+    auto load_result = load_certificates(s_default_ca_certificate_paths);
     if (load_result.is_error()) {
         dbgln("Failed to load CA Certificates: {}", load_result.error());
         return;
@@ -571,7 +574,7 @@ DefaultRootCACertificates& DefaultRootCACertificates::the()
     return s_the;
 }
 
-ErrorOr<Vector<Certificate>> DefaultRootCACertificates::load_certificates(StringView custom_cert_path)
+ErrorOr<Vector<Certificate>> DefaultRootCACertificates::load_certificates(Span<ByteString> custom_cert_paths)
 {
     auto cacert_file_or_error = Core::File::open("/etc/cacert.pem"sv, Core::File::OpenMode::Read);
     ByteBuffer data;
@@ -588,9 +591,11 @@ ErrorOr<Vector<Certificate>> DefaultRootCACertificates::load_certificates(String
         TRY(data.try_append(TRY(user_cert_file->read_until_eof())));
     }
 
-    if (!custom_cert_path.is_empty() && FileSystem::exists(custom_cert_path)) {
-        auto custom_cert_file = TRY(Core::File::open(custom_cert_path, Core::File::OpenMode::Read));
-        TRY(data.try_append(TRY(custom_cert_file->read_until_eof())));
+    for (auto& custom_cert_path : custom_cert_paths) {
+        if (FileSystem::exists(custom_cert_path)) {
+            auto custom_cert_file = TRY(Core::File::open(custom_cert_path, Core::File::OpenMode::Read));
+            TRY(data.try_append(TRY(custom_cert_file->read_until_eof())));
+        }
     }
 
     return TRY(parse_pem_root_certificate_authorities(data));

+ 1 - 0
Userland/Services/RequestServer/main.cpp

@@ -34,6 +34,7 @@ ErrorOr<int> serenity_main(Main::Arguments)
         TRY(Core::System::pledge("stdio inet accept unix rpath sendfd recvfd"));
 
     // Ensure the certificates are read out here.
+    // FIXME: Allow specifying extra certificates on the command line, or in other configuration.
     [[maybe_unused]] auto& certs = DefaultRootCACertificates::the();
 
     Core::EventLoop event_loop;

+ 1 - 0
Userland/Services/WebSocket/main.cpp

@@ -17,6 +17,7 @@ ErrorOr<int> serenity_main(Main::Arguments)
     TRY(Core::System::pledge("stdio inet unix rpath sendfd recvfd"));
 
     // Ensure the certificates are read out here.
+    // FIXME: Allow specifying extra certificates on the command line, or in other configuration.
     [[maybe_unused]] auto& certs = DefaultRootCACertificates::the();
 
     Core::EventLoop event_loop;