diff --git a/lib/private/Security/CertificateManager.php b/lib/private/Security/CertificateManager.php index ee9332e550fac..789e81ff1bc20 100644 --- a/lib/private/Security/CertificateManager.php +++ b/lib/private/Security/CertificateManager.php @@ -15,9 +15,6 @@ use OCP\Security\ISecureRandom; use Psr\Log\LoggerInterface; -/** - * Manage trusted certificates for users - */ class CertificateManager implements ICertificateManager { private ?string $bundlePath = null; @@ -29,11 +26,6 @@ public function __construct( ) { } - /** - * Returns all certificates trusted by the user - * - * @return ICertificate[] - */ #[\Override] public function listCertificates(): array { if (!$this->config->getSystemValueBool('installed', false)) { @@ -67,6 +59,9 @@ public function listCertificates(): array { return $result; } + /** + * Check whether any uploaded certificates are present. + */ private function hasCertificates(): bool { if (!$this->config->getSystemValueBool('installed', false)) { return false; @@ -91,9 +86,14 @@ private function hasCertificates(): bool { } /** - * create the certificate bundle of all trusted certificated + * Rebuild the generated effected certificate bundle from: + * - uploaded certificates + * - the shipped default CA bundle + * - the current system CA bundle, if present and different from the target + * + * The bundle is written atomically to /files_external/rootcerts.crt. */ - public function createCertificateBundle(): void { + private function createCertificateBundle(): void { $path = $this->getPathToCertificates(); $certs = $this->listCertificates(); @@ -142,13 +142,6 @@ public function createCertificateBundle(): void { $this->view->rename($tmpPath, $certPath); } - /** - * Save the certificate and re-generate the certificate bundle - * - * @param string $certificate the certificate data - * @param string $name the filename for the certificate - * @throws \Exception If the certificate could not get added - */ #[\Override] public function addCertificate(string $certificate, string $name): ICertificate { $path = $this->getPathToCertificates() . 'uploads/' . $name; @@ -171,9 +164,6 @@ public function addCertificate(string $certificate, string $name): ICertificate } } - /** - * Remove the certificate and re-generate the certificate bundle - */ #[\Override] public function removeCertificate(string $name): bool { $path = $this->getPathToCertificates() . 'uploads/' . $name; @@ -192,18 +182,11 @@ public function removeCertificate(string $name): bool { return true; } - /** - * Get the path to the certificate bundle - */ #[\Override] public function getCertificateBundle(): string { return $this->getPathToCertificates() . 'rootcerts.crt'; } - /** - * Get the full local path to the certificate bundle - * @throws \Exception when getting bundle path fails - */ #[\Override] public function getAbsoluteBundlePath(): string { try { @@ -230,12 +213,20 @@ public function getAbsoluteBundlePath(): string { } } + /** + * Get the base path used to store uploaded certificates and the generated bundle. + * + * The uploaded certificates and generated bundle are stored under the + * files_external path for historical reasons, maintaining compatibility + * with pre-existing deployments. + */ private function getPathToCertificates(): string { return '/files_external/'; } /** - * Check if we need to re-bundle the certificates because one of the sources has updated + * Determine whether the generated bundle must be rebuilt because the source + * CA bundle has changed or the target bundle is missing. */ private function needsRebundling(): bool { $targetBundle = $this->getCertificateBundle(); @@ -248,7 +239,7 @@ private function needsRebundling(): bool { } /** - * get mtime of ca-bundle shipped by Nextcloud + * Return the modification time of the shipped default CA bundle. */ protected function getFilemtimeOfCaBundle(): int { return filemtime($this->getDefaultCertificatesBundlePath()); diff --git a/lib/public/ICertificateManager.php b/lib/public/ICertificateManager.php index be4afc799fa63..f8249b5a923e8 100644 --- a/lib/public/ICertificateManager.php +++ b/lib/public/ICertificateManager.php @@ -9,12 +9,20 @@ namespace OCP; /** - * Manage trusted certificates + * Manage trusted certificates and the effective CA bundle used by Nextcloud. + * + * Implementations provide access to uploaded trusted certificates and the + * generated bundle that is consumed by HTTP clients and external storage + * integrations. + * * @since 8.0.0 */ interface ICertificateManager { /** - * Returns all certificates trusted by the system + * Returns all uploaded trusted certificates. + * + * This does not include the shipped default CA bundle or any system CA bundle + * appended when building the effective bundle. * * @return \OCP\ICertificate[] * @since 8.0.0 @@ -22,23 +30,27 @@ interface ICertificateManager { public function listCertificates(): array; /** - * @param string $certificate the certificate data - * @param string $name the filename for the certificate + * Add a trusted certificate to the certificate store. + * + * @param string $certificate The certificate data in PEM format + * @param string $name The filename for the certificate * @return \OCP\ICertificate - * @throws \Exception If the certificate could not get added + * @throws \Exception If the certificate could not be added * @since 8.0.0 - since 8.1.0 throws exception instead of returning false */ public function addCertificate(string $certificate, string $name): \OCP\ICertificate; /** - * @param string $name + * Remove a trusted certificate from the certificate store. + * + * @param string $name The filename for the certificate * @return bool * @since 8.0.0 */ public function removeCertificate(string $name): bool; /** - * Get the path to the certificate bundle + * Get the relative path to the generated certificate bundle. * * @return string * @since 8.0.0 @@ -46,7 +58,10 @@ public function removeCertificate(string $name): bool; public function getCertificateBundle(): string; /** - * Get the full local path to the certificate bundle + * Get the full local path to the effective certificate bundle. + * + * Implementations should return the generated bundle path, but may log and fall back + * to the shipped default CA bundle if resolution fails. * * @return string * @since 9.0.0 @@ -54,7 +69,7 @@ public function getCertificateBundle(): string; public function getAbsoluteBundlePath(): string; /** - * Get the path of the default certificates bundle. + * Get the path of the shipped default certificates bundle. * * @since 33.0.0 */