From 914fe5322e7050897126edcdb6664f2b42453134 Mon Sep 17 00:00:00 2001 From: Flo Schuessel Date: Mon, 19 Jan 2026 12:21:15 +0100 Subject: [PATCH] feat(ca): Improve root privilege handling for macOS trust operations - Modify macOS CA trust management to handle root and non-root scenarios more gracefully. - Add isRoot() function to detect current process privileges. - Update InstallTrust(), UninstallTrust(), and IsTrusted() methods to conditionally use sudo and improve certificate verification logic. --- CHANGELOG.md | 7 +++++ internal/ca/trust_darwin.go | 63 +++++++++++++++++++++++++++---------- 2 files changed, 54 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a448b54..947b5d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Unreleased + +### Changed + +- Root privilege handling is improved +- Verification of Root CA certificate is more reliable + ## 0.2.0 2026-01-18 ### Added diff --git a/internal/ca/trust_darwin.go b/internal/ca/trust_darwin.go index 554a0ba..4a5aa1e 100644 --- a/internal/ca/trust_darwin.go +++ b/internal/ca/trust_darwin.go @@ -7,10 +7,16 @@ package ca import ( "bytes" "fmt" + "os" "os/exec" "strings" ) +// isRoot returns true if the current process is running as root. +func isRoot() bool { + return os.Geteuid() == 0 +} + // InstallTrust adds the CA certificate to the macOS System Keychain. // This requires sudo/admin privileges. func InstallTrust() error { @@ -29,12 +35,23 @@ func InstallTrust() error { // -d: add to admin cert store // -r trustRoot: trust as root certificate // -k: keychain to add to - cmd := exec.Command("sudo", "security", "add-trusted-cert", - "-d", - "-r", "trustRoot", - "-k", "/Library/Keychains/System.keychain", - certPath, - ) + var cmd *exec.Cmd + if isRoot() { + // Already running as root, no need for sudo + cmd = exec.Command("security", "add-trusted-cert", + "-d", + "-r", "trustRoot", + "-k", "/Library/Keychains/System.keychain", + certPath, + ) + } else { + cmd = exec.Command("sudo", "security", "add-trusted-cert", + "-d", + "-r", "trustRoot", + "-k", "/Library/Keychains/System.keychain", + certPath, + ) + } var stderr bytes.Buffer cmd.Stderr = &stderr @@ -50,11 +67,19 @@ func InstallTrust() error { // This requires sudo/admin privileges. func UninstallTrust() error { // Find and delete the certificate by name - // First, we need to find the SHA-1 hash of our certificate - cmd := exec.Command("sudo", "security", "delete-certificate", - "-c", caCommonName, - "/Library/Keychains/System.keychain", - ) + var cmd *exec.Cmd + if isRoot() { + // Already running as root, no need for sudo + cmd = exec.Command("security", "delete-certificate", + "-c", caCommonName, + "/Library/Keychains/System.keychain", + ) + } else { + cmd = exec.Command("sudo", "security", "delete-certificate", + "-c", caCommonName, + "/Library/Keychains/System.keychain", + ) + } var stderr bytes.Buffer cmd.Stderr = &stderr @@ -77,13 +102,19 @@ func IsTrusted() bool { return false } - // Use security verify-cert to check if the CA is actually trusted - // This verifies the trust chain, not just presence in keychain - cmd := exec.Command("security", "verify-cert", - "-c", CertPath(), + // Check if the certificate exists in the System Keychain + // This is the correct way to verify installation, not verify-cert + // (verify-cert returns success for self-signed CAs even if not installed) + cmd := exec.Command("security", "find-certificate", + "-c", caCommonName, + "/Library/Keychains/System.keychain", ) - // verify-cert returns 0 if trusted, non-zero otherwise + // Suppress output - we only care about the exit code + cmd.Stdout = nil + cmd.Stderr = nil + + // find-certificate returns 0 if found, non-zero otherwise return cmd.Run() == nil }