通過開源、多平臺程式碼簽名擴充套件 Apple 生態系統訪問許可權

語言: CN / TW / HK

蘋果系統執行著一些現有的最大和最賺錢的軟體應用程式生態系統。理論上,要進入這些生態系統,傳統上需要使用macOS,並加入蘋果開發者計劃(Apple Developer Program)。

如果你想為 Apple 作業系統開發應用程式,你可能會使用 Apple 的作業系統和 Apple 的官方工具進行開發和分發。但對於開源開發人員通常希望以最小的努力分發跨平臺應用程式。在整個程式語言生態系統中,你執行的作業系統被抽象為許多應用程式的實現細節。通過建立 macOS、iOS 等開發需要直接訪問 macOS 和通常高於市場價格的Apple 硬體的要求,蘋果軟體生態系統強加的分發要求是有效的排他性,並阻止利益相關方對進入其生態系統。

在蘋果平臺上釋出軟體的一個問題是程式碼簽署和公證,即你需要:

1.在應用程式中嵌入加密簽名,有效地證明來自 Apple Developer Program 關聯帳戶的真實性。 (這是簽名。)

2.將你的應用程式上傳到 Apple,以便他們對其進行檢查,驗證它符合要求,可能還會儲存一個副本。然後,蘋果會發布自己的加密簽名,即公證書,然後需要將其嵌入到正在分發的應用程式上,這樣蘋果的作業系統才能信任它。(這是公證。)

從歷史上看,這些步驟需要 Apple 專有軟體專門從 macOS 執行。這意味著,即使你在 Rust、Go 等軟體生態系統或 Web 平臺中,你可以在不直接訪問 macOS 的情況下交叉編譯應用程式(測試顯然是另一回事),如果你願意,你仍然需要 macOS簽署和公證你的申請。由於預設的安全設定,在macOS上需要有效的簽名和公證。在 iOS 等移動平臺上,除非你執行的是越獄裝置,否則不可能釋出未經簽名和公證的應用程式。

如果我不需要macOS來構建我的應用程式,為什麼我要被迫把蘋果裝置作為我的軟體釋出過程的一部分?為什麼在釋出的時候,我必須簽署和公證我的申請,它不能更簡化嗎?

如果能重新實現 Apple 程式碼簽名,以便開發人員有更多的靈活性和機會將應用程式分發到 Apple 的生態系統。其最終目標是擴大 Apple 生態系統對更多開發者的訪問。

首先,得益於 rcodesign 0.14.0的釋出。這是我第一次釋出 rcodesign 的預構建二進位制檔案(Linux、Windows 和 macOS)。

macOS rcodesign 可執行檔案是自簽名的,它由 GitHub Actions Linux 執行程式使用 YubiKey 獨有的程式碼簽名證書進行簽名。

2021年,apple-codesign 專案/Rust crate 發生了很大變化!只需檢視更改日誌!

這個專案從tugger-apple-codesign改名而來。

如果你是通過 cargo install 安裝的,你需要 cargo install --force apple-codesign 來強制 Cargo 用另一個 crate 中的一個來覆蓋 rcodesign 可執行檔案。

rcodesign CLI可執行檔案仍然存在,而且比以往任何時候都更強大。你仍然可以在Linux、Windows、macOS和任何其他平臺上對Apple應用程式進行簽名,你可以在這些平臺上編譯Rust程式。

這與 PyOxidizer 的文件一起釋出在 readthedocs.io 上(因為我使用的是 monorepo)。那裡有一些通用文件,例如有關如何通過將你自己的替代程式碼簽名 PKI 部署到並行 Apple 來選擇性地繞過 Gatekeeper 的指南。

支援簽名包、DMG 和 .pkg 安裝程式

當我去年宣佈這個專案時,只有 Mach-O 二進位制檔案和非常簡單的 .app 包是可簽名的。即便如此,也有很多微妙的問題。

Rcodesign sign現在可以對更復雜的包進行簽名,包括許多巢狀的包。有報道稱iOS應用包簽名正確。

該工具還支援簽名.dmg磁碟映像檔案和.pkg扁平封裝包安裝程式。

已知的簽名限制現在記錄在 Sphinx 文件中。

我相信 rcodesign 現在支援對用於 Apple 軟體分發的所有主要檔案格式進行簽名。

支援 Linux、Windows 和 macOS 上的公證

蘋果釋出了一個名為Transporter的Java工具,可以讓你上傳文物到蘋果進行公證。它們使這個工具可用於Linux、Windows,當然還有macOS。

雖然這個工具不是開源的,但使用這個工具可以讓你在 Linux 和 Windows 上進行公證,同時仍然使用 Apple 的官方工具與他們的伺服器通訊。

rcodesign 現在支援呼叫 Transporter 並將工件上傳到 Apple 進行公證。我們現在支援公證包、.dmg 磁碟映像和 .pkg 扁平封裝安裝程式包。我已經成功地從 Linux 公證了所有這些應用程式型別。

由於支援對所有應用程式型別進行簽名和公證,現在可以在沒有 macOS 參與釋出過程的情況下發布 Apple 軟體。

YubiKey 整合

我嘗試儘可能多地使用我的 YubiKey,因為儲存在 YubiKey 上的金鑰或私鑰可能比位於某個檔案系統上的金鑰或私鑰更安全。如果你破解了我的裝置,你很可能會獲得我的私鑰。但是你需要物理訪問我的 YubiKey 並強迫或強迫我解鎖它,以獲得訪問其私鑰的許可權。

rcodesign 現在支援使用 YubiKeys 進行簽名操作。

這確實需要預設的智慧卡 Cargo 功能。因此,如果手動構建,你將需要例如cargo install --features smartcard apple-codesign.。

YubiKey 整合來自 yubikey 。這個 crate 將直接與 macOS 和 Windows 中內建的智慧卡 API 對話。所以如果你有一個啟用了 YubiKey 支援的 rcodesign 構建,YubiKeys 應該可以工作。通過插入 YubiKey 並執行 rcodesign smartcard-scan 進行嘗試。

我甚至實現了一些命令來輕鬆管理 YubiKey 上的程式碼簽名證書。例如,你可以直接在裝置上執行 rcodesign smartcard-generate-key --smartcard-slot 9c 以生成新的私鑰,然後  rcodesign generate-certificate-signing-request --smartcard-slot 9c --csr-pem-path csr.pem將該證書匯出到證書籤名請求 (CSR),你可以在 developer.apple.com 上交換 Applie 頒發的簽名證書。這意味著你可以輕鬆建立其私鑰直接在硬體裝置上生成且永遠無法匯出的程式碼簽名證書。以這種方式生成金鑰比將金鑰儲存在軟體庫(比如蘋果的Keychains)中更安全。

遠端程式碼簽名

我最感興趣的功能是我稱之為遠端程式碼簽名的功能。

我在GitHub託管的Linux GitHub Actions執行程式上籤署了一個macOS通用Mach-O可執行檔案,使用的YubiKey物理連線到我桌子旁邊的Windows 11裝置上。未在計算機之間複製簽名的應用程式。

我有一個呼叫 rcodesign sign --remote-signer 的 GitHub Actions 工作流程。我手動觸發了該工作流程,並開始使用瀏覽器觀察近乎實時的作業輸出。rcodesign sign --remote-signer 打印出一些指令(包括一堵 base64 編碼資料的牆)以指示下一步該做什麼。重要的是,它要求其他人執行 rcodesign remote-sign 以繼續簽名過程。

該日誌向我們展示了使用 YubiKey 進行連線和身份驗證,以及一些關於與遠端伺服器對話的狀態更新。

遠端簽名使我能夠從 GitHub 運營的 GitHub Actions 執行程式簽署 macOS 應用程式,同時使用安全儲存在我的 YubiKey 上的程式碼簽名證書,該證書插入到距 GitHub Actions 執行程式數百公里的 Windows 裝置上。

這裡發生的是 2 個 rcodesign 程序通過中央中繼伺服器橋接的 websocket 相互通訊。我免費操作一個預設伺服器。伺服器是開源的,如果你想執行你自己的伺服器,你可以使用terrform模組,希望只需要花幾分鐘時間。當啟動裝置希望建立簽名時,它向請求加密簽名的簽名者傳送一條訊息。然後將簽名傳送回發起者,發起者將其合併。

我設計這個特性時考慮到了CI系統的自動釋出(比如GitHub Actions)。我想要一種方法,可以簡化應用程式的程式碼簽名和釋出過程,而不必給CI中的低信任裝置無限訪問我的私人簽名金鑰的許可權。這可能在許多其他場景中都是有用的。你是否曾經因為沒有蘋果發行的程式碼簽名證書而通過電子郵件或下拉框將應用程式傳送給別人簽名?現在你有了一個不需要複製檔案的替代解決方案。只要你可以看到啟動裝置的日誌輸出,或者將輸出傳遞給你(例如通過聊天應用程式或電子郵件),你就可以在另一臺裝置上遠端簽署檔案!

關於遠端簽名安全性

Websockets 通過由第三方操作的中央伺服器?!授予遠端裝置訪問許可權以對任意內容執行程式碼簽名?!你的恐懼和懷疑是 100% 有道理的:我也會這麼想!

促進遠端程式碼簽名的服務會成為一個非常有利可圖的攻擊目標,如果被濫用,它可能被用來強制使用有效的程式碼簽名證書的各方簽署不想要的程式碼,如惡意軟體。實現這樣的功能有很多很多很多錯誤的方法。

遠端程式碼簽名設計和安全注意事項包含了我的一些高階設計目標和安全評估。遠端程式碼簽名協議詳細介紹了通訊協議,包括所涉及的加密(實際的加密,而不是流行的加密)。關鍵在於協議和伺服器的設計使惡意伺服器或中間人無法偽造簽名請求。簽名會話在幾分鐘後過期,第三方或伺服器無法注入會導致不需要簽名的惡意訊息。通過初始握手獲得會話臨時共享加密金鑰,並從那裡使用對稱加密金鑰,因此對等方之間的所有有意義的訊息都是端到端加密的。惡意伺服器可以做的最糟糕的事情就是進行拒絕服務。

我相信我的遠端簽名實現比許多常見做法更安全,因為今天的常見做法需要複製私鑰並讓低信任度裝置(如 CI 工作人員)訪問私鑰或者檔案在沒有加密監管鏈的情況下被複制以證明不會被篡改。是的,遠端簽名為遠端訪問引入了使用簽名金鑰的向量。但是按照我的意圖進行實踐,遠端簽名可以消除複製私鑰或授予對它們的無限訪問許可權的需要。從威脅建模的角度來看,我認為金鑰訪問中的網路限制使得遠端簽名比現在許多人使用的私鑰管理實踐更安全。

話雖如此,這裡的星號是我實現了我自己的密碼系統來實現端到端訊息安全。如果在設計或實現中存在漏洞,密碼系統可能會崩潰,從而帶來對訊息偽造的防禦。屆時,惡意伺服器或特權網路攻擊者可能會強迫某人簽署不需要的軟體。但這很可能是損害的程度:對簽名金鑰的離線攻擊是不可能的,因為簽名需要存在,而且私鑰永遠不會通過網路傳輸。即使沒有端到端加密,該系統也比將你的私有金鑰作為一個容易被竊取的CI祕密(或類似的)留在周圍更安全。

Apple 鑰匙串支援

從0.14 版本開始,我們現在可以提前支援使用儲存在 Apple 鑰匙串中的程式碼簽名證書進行簽名!如果你在 Keychain Access 或 Xcode 中建立了 Apple 程式碼簽名證書,那麼這可能就是你的程式碼簽名證書所在的位置。

我拖延了很長一段時間,因為我沒有意識到這有什麼好處:如果你使用macOS,只需使用 蘋果的官方工具。但是隨著rcodesign獲得了對遠端程式碼簽名的支援,以及其他一些功能,這些功能可以讓它成為所有平臺上蘋果工具的有力替代品,我認為我們應該提供這個功能,這樣我們就不會再阻止人們從keychain匯出私鑰了。

Apple 的程式碼簽名很複雜。 蘋果的工具和rcodesign之間很容易出現細微差別。

rcodesign 現在有 print-signature-info 和 diff-signatures 命令來轉儲和比較與程式碼簽名相關的 YAML 元資料,以便更容易地比較程式碼簽名實現甚至多個簽名操作之間的行為。

本文翻譯自:https://gregoryszorc.com/blog/2022/04/25/expanding-apple-ecosystem-access-with-open-source,-multi-platform-code-signing/如若轉載,請註明原文地址。