簽名驗證 (Signature Verification) 成品簽名 (Artifact signing) 允許您驗證所擁有的成品與專案工作流建立的成品相同,且未被未經授權的第三方(例如中間人)修改。驗證為所有參與方提供了一個共同基礎、保證和知識,確保大家引用的是同一個成品、同一個位元組集合,無論它是執行檔、SBOM 還是文字檔。 從 Caddy v2.6.0 開始,CI/CD 發佈成品使用專案 Sigstore 技術進行簽名,該技術會發行包含有關憑證發行對象詳細資訊的憑證。您可以從檢查用於簽名您所選成品的憑證開始。憑證是 base64 編碼的,因此您必須先對其進行 base64 解碼才能收到 PEM 檔案。在本範例中,我們將使用 caddy_2.6.0_checksums.txt 成品並假設使用類 Linux 環境。 首先下載與您選擇的成品相關的 3 個檔案(即 <成品>,它是要驗證其伴隨簽名和憑證的實際成品;<成品>.sig,它是成品的簽名;以及 <成品>.pem,它是源自 Sigstore Fulcio 根憑證的憑證)。然後將下載的 .pem 檔案 base64 解碼為裝甲版本 (armored version): base64 -d < caddy_2.6.0_checksums.txt.pem > cert.pem 您現在可以使用 openssl 命令檢查憑證。對我們剛剛解碼的憑證執行 openssl x509 -in cert.pem -text 會顯示以下剪輯後的列印輸出: openssl x509 -in cert.pem -text Certificate: Data: Version: 3 (0x2) Serial Number: 22:b0:45:9d:ad:d7:54:98:67:66:b7:de:31:01:ef:4a:02:ab:fb:60 Signature Algorithm: ecdsa-with-SHA384 Issuer: O=sigstore.dev, CN=sigstore-intermediate Validity Not Before: Sep 20 17:17:06 2022 GMT Not After : Sep 20 17:27:06 2022 GMT Subject: Subject Public Key Info: Public Key Algorithm: id-ecPublicKey Public-Key: (256 bit) pub: 04:22:ee:f6:b1:85:1c:de:cf:90:1d:91:75:36:c4: 82:9d:54:5e:f3:a6:5b:3f:18:89:8a:0b:de:d8:93: 7c:02:40:39:00:d4:4e:19:0b:30:93:cc:a4:d0:df: 35:f7:b1:08:24:89:cf:3a:38:06:ff:92:75:06:84: b5:9e:25:8c:9a ASN1 OID: prime256v1 NIST CURVE: P-256 X509v3 extensions: X509v3 Key Usage: critical Digital Signature X509v3 Extended Key Usage: Code Signing X509v3 Subject Key Identifier: 3B:C0:D1:D2:C8:BA:2D:55:95:1F:68:78:DC:C6:2C:D9:B5:17:0E:EA X509v3 Authority Key Identifier: keyid:DF:D3:E9:CF:56:24:11:96:F9:A8:D8:E9:28:55:A2:C6:2E:18:64:3F X509v3 Subject Alternative Name: critical URI:https://github.com/caddyserver/caddy/.github/workflows/release.yml@refs/tags/v2.6.0 1.3.6.1.4.1.57264.1.1: https://token.actions.githubusercontent.com 1.3.6.1.4.1.57264.1.2: push 1.3.6.1.4.1.57264.1.3: 821a08a6e39ed0e7c43b0271ccf126c194eb6339 1.3.6.1.4.1.57264.1.4: Release 1.3.6.1.4.1.57264.1.5: caddyserver/caddy 1.3.6.1.4.1.57264.1.6: refs/tags/v2.6.0 1.3.6.1.4.1.11129.2.4.2: .z.x.v..`..(R.hE..k'..Eg...=.8.m..".6or....[.DS.....G0E.!..>MD.a..B.p..^..P*...um.....X..F. NYy.....#...TWIZ...y..qa....4P.. Signature Algorithm: ecdsa-with-SHA384 30:66:02:31:00:be:b3:3c:15:56:78:64:c6:0f:bc:48:69:a9: 0a:27:cd:4d:92:39:00:50:42:a8:2a:ad:11:4d:64:f2:61:35: ec:08:e9:b5:6a:14:1b:f6:c1:0e:46:ee:a0:54:08:26:e1:02: 31:00:a7:6d:97:db:4c:c8:dd:47:13:3d:28:7a:a6:f3:64:50: 2c:5a:9d:9d:10:d0:cf:6f:d0:e9:37:76:fd:cc:8e:9d:c3:6b: ba:78:07:40:6a:40:d6:db:f6:97:d5:6a:36:9d -----BEGIN CERTIFICATE----- MIIDlDCCAxmgAwIBAgIUIrBFna3XVJhnZrfeMQHvSgKr+2AwCgYIKoZIzj0EAwMw NzEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MR4wHAYDVQQDExVzaWdzdG9yZS1pbnRl cm1lZGlhdGUwHhcNMjIwOTIwMTcxNzA2WhcNMjIwOTIwMTcyNzA2WjAAMFkwEwYH KoZIzj0CAQYIKoZIzj0DAQcDQgAEIu72sYUc3s+QHZF1NsSCnVRe86ZbPxiJigve 2JN8AkA5ANROGQswk8yk0N8197EIJInPOjgG/5J1BoS1niWMmqOCAjgwggI0MA4G A1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzAdBgNVHQ4EFgQUO8DR 0si6LVWVH2h43MYs2bUXDuowHwYDVR0jBBgwFoAU39Ppz1YkEZb5qNjpKFWixi4Y ZD8wYQYDVR0RAQH/BFcwVYZTaHR0cHM6Ly9naXRodWIuY29tL2NhZGR5c2VydmVy L2NhZGR5Ly5naXRodWIvd29ya2Zsb3dzL3JlbGVhc2UueW1sQHJlZnMvdGFncy92 Mi42LjAwOQYKKwYBBAGDvzABAQQraHR0cHM6Ly90b2tlbi5hY3Rpb25zLmdpdGh1 YnVzZXJjb250ZW50LmNvbTASBgorBgEEAYO/MAECBARwdXNoMDYGCisGAQQBg78w AQMEKDgyMWEwOGE2ZTM5ZWQwZTdjNDNiMDI3MWNjZjEyNmMxOTRlYjYzMzkwFQYK KwYBBAGDvzABBAQHUmVsZWFzZTAfBgorBgEEAYO/MAEFBBFjYWRkeXNlcnZlci9j YWRkeTAeBgorBgEEAYO/MAEGBBByZWZzL3RhZ3MvdjIuNi4wMIGKBgorBgEEAdZ5 AgQCBHwEegB4AHYACGCS8ChS/2hF0dFrJ4ScRWcYrBY9wzjSbea8IgY2b3IAAAGD W+dEUwAABAMARzBFAiEAnD5NRKZhFLhCHHDIzV6bwVAqlYP6dW0CwKWDo1jzmEYC IE5ZeeK14oi6I+7z2VRXSVq4/r15GAFxYaCMFrI0UOjjMAoGCCqGSM49BAMDA2kA MGYCMQC+szwVVnhkxg+8SGmpCifNTZI5AFBCqCqtEU1k8mE17AjptWoUG/bBDkbu oFQIJuECMQCnbZfbTMjdRxM9KHqm82RQLFqdnRDQz2/Q6Td2/cyOncNrungHQGpA 1tv2l9VqNp0= -----END CERTIFICATE----- 現在我們有了憑證,我們可以使用 cosign cli 來驗證簽名。我們執行以下命令(注意它使用的是未解碼的憑證): COSIGN_EXPERIMENTAL=1 cosign verify-blob --certificate ./caddy_2.6.0_checksums.txt.pem --signature ./caddy_2.6.0_checksums.txt.sig ./caddy_2.6.0_checksums.txt tlog entry verified with uuid: 04deb84e5a73ba75ea69092c6d700eaeb869c29cae3e0cf98dbfef871361ed09 index: 3618623 Verified OK 現在讓我們切換 cli 工具並使用 rekor-cli,它與儲存透明度日誌 (transparency logs) 的公共 Rekor 伺服器進行互動。讓我們執行: rekor-cli get --uuid 04deb84e5a73ba75ea69092c6d700eaeb869c29cae3e0cf98dbfef871361ed09 --format json | jq -r '.' 使用 jq 是為了美化輸出。您應該會看到如下輸出: { "Attestation": "", "AttestationType": "", "Body": { "HashedRekordObj": { "data": { "hash": { "algorithm": "sha256", "value": "508f1044ecd9f14c43c6c8986b45b90fc79f25736e2bc85c0911433ce82533f2" } }, "signature": { "content": "MEUCIHGL2HP5XzcUESTxIk72FS1aNK54LesTfyo+dVhRMeduAiEAnWZDZ5Ur44Y9056vr4to2Fb9FteG53eAFotv3fUZ4h4=", "publicKey": { "content": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURsRENDQXhtZ0F3SUJBZ0lVSXJCRm5hM1hWSmhuWnJmZU1RSHZTZ0tyKzJBd0NnWUlLb1pJemowRUF3TXcKTnpFVk1CTUdBMVVFQ2hNTWMybG5jM1J2Y21VdVpHVjJNUjR3SEFZRFZRUURFeFZ6YVdkemRHOXlaUzFwYm5SbApjbTFsWkdsaGRHVXdIaGNOTWpJd09USXdNVGN4TnpBMldoY05Nakl3T1RJd01UY3lOekEyV2pBQU1Ga3dFd1lICktvWkl6ajBDQVFZSUtvWkl6ajBEQVFjRFFnQUVJdTcyc1lVYzNzK1FIWkYxTnNTQ25WUmU4NlpiUHhpSmlndmUKMkpOOEFrQTVBTlJPR1Fzd2s4eWswTjgxOTdFSUpJblBPamdHLzVKMUJvUzFuaVdNbXFPQ0FqZ3dnZ0kwTUE0RwpBMVVkRHdFQi93UUVBd0lIZ0RBVEJnTlZIU1VFRERBS0JnZ3JCZ0VGQlFjREF6QWRCZ05WSFE0RUZnUVVPOERSCjBzaTZMVldWSDJoNDNNWXMyYlVYRHVvd0h3WURWUjBqQkJnd0ZvQVUzOVBwejFZa0VaYjVxTmpwS0ZXaXhpNFkKWkQ4d1lRWURWUjBSQVFIL0JGY3dWWVpUYUhSMGNITTZMeTluYVhSb2RXSXVZMjl0TDJOaFpHUjVjMlZ5ZG1WeQpMMk5oWkdSNUx5NW5hWFJvZFdJdmQyOXlhMlpzYjNkekwzSmxiR1ZoYzJVdWVXMXNRSEpsWm5NdmRHRm5jeTkyCk1pNDJMakF3T1FZS0t3WUJCQUdEdnpBQkFRUXJhSFIwY0hNNkx5OTBiMnRsYmk1aFkzUnBiMjV6TG1kcGRHaDEKWW5WelpYSmpiMjUwWlc1MExtTnZiVEFTQmdvckJnRUVBWU8vTUFFQ0JBUndkWE5vTURZR0Npc0dBUVFCZzc4dwpBUU1FS0RneU1XRXdPR0UyWlRNNVpXUXdaVGRqTkROaU1DIEMvYmJEa2J1Cm9GUUlKdUVDTVFDbmJaZmJUTWpkUnhNOUtIcW04MlJRTEZxZG5SRFF6Mi9RNlRkMi9jeU9uY05ydW5nSFFHcEEKMXR2Mmw5VnFOcDA9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K" } } }, "LogIndex": 3618623, "IntegratedTime": 1663694226, "UUID": "04deb84e5a73ba75ea69092c6d700eaeb869c29cae3e0cf98dbfef871361ed09", "LogID": "c0d23d6ad406973f9559f3ba2d1ca01f84147d8ffc5b8445c224f98b9591801d" } 請注意 .Body.HashedRekordObj.signature.content 的值如何與我們在 CI 中產生並可在檔案 caddy_2.6.0_checksums.txt.sig 中找到的簽名內容相匹配。此外,所使用和下載的憑證也儲存在 Rekor 伺服器中,並可在回應中的 .Body.HashedRekordObj.signature.publicKey.content 處獲得,且與我們在檔案 caddy_2.6.0_checksums.txt.pem 中的字串相匹配。我們可以更進一步,檢查 .Body.HashedRekordObj.data.hash.value 如何與命令 sha256sum ./caddy_2.6.0_checksums.txt 的輸出相匹配。因此,到目前為止,我們有了匹配的憑證、匹配的簽名和匹配的校驗和(包含檔案歸檔校驗和但非其本身的檔案;此校驗和是透過 Sigstore 生態系統從外部提供和記錄的)。所有這一切都公開記錄在透明度日誌中,供公眾驗證。 驗證成品的真實性 如果您拿到一個聲稱為 Caddy 專案產品的成品,但沒有收到簽名檔案或憑證怎麼辦?您可以使用 rekor-cli 向 Rekor 伺服器查詢該成品: rekor-cli search --artifact ./caddy_2.6.0_checksums.txt --format json | jq -r '.UUIDs[0]' Found matching entries (listed by UUID): 362f8ecba72f432604deb84e5a73ba75ea69092c6d700eaeb869c29cae3e0cf98dbfef871361ed09 請注意 UUID 如何與前一節中針對同一檔案遇到的 UUID 相匹配。就像我們在前一節中所做的那樣,我們可以查詢 Rekor 以獲取此 UUID 的條目詳細資訊: rekor-cli get --uuid 04deb84e5a73ba75ea69092c6d700eaeb869c29cae3e0cf98dbfef871361ed09 --format json | jq -r '.' 然而,我們可以透過執行這行代碼將兩個單獨的命令合併為一行來縮短查找過程: rekor-cli get --uuid $(rekor-cli search --artifact ./caddy_2.6.0_checksums.txt --format json | jq -r '.UUIDs[0]') --format json | jq -r '.' { "Attestation": "", "AttestationType": "", "Body": { "HashedRekordObj": { "data": { "hash": { "algorithm": "sha256", "value": "508f1044ecd9f14c43c6c8986b45b90fc79f25736e2bc85c0911433ce82533f2" } }, "signature": { "content": "MEUCIHGL2HP5XzcUESTxIk72FS1aNK54LesTfyo+dVhRMeduAiEAnWZDZ5Ur44Y9056vr4to2Fb9FteG53eAFotv3fUZ4h4=", "publicKey": { "content": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURsRENDQXhtZ0F3SUJBZ0lVSXJCRm5hM1hWSmhuWnJmZU1RSHZTZ0tyKzJBd0NnWUlLb1pJemowRUF3TXcKTnpFVk1CTUdBMVVFQ2hNTWMybG5jM1J2Y21VdVpHVjJNUjR3SEFZRFZRUURFeFZ6YVdkemRHOXlaUzFwYm5SbApjbTFsWkdsaGRHVXdIaGNOTWpJd09USXdNVGN4TnpBMldoY05Nakl3T1RJd01UY3lOekEyV2pBQU1Ga3dFd1lICktvWkl6ajBDQVFZSUtvWkl6ajBEQVFjRFFnQUVJdTcyc1lVYzNzK1FIWkYxTnNTQ25WUmU4NlpiUHhpSmlndmUKMkpOOEFrQTVBTlJPR1Fzd2s4eWswTjgxOTdFSUpJblBPamdHLzVKMUJvUzFuaVdNbXFPQ0FqZ3dnZ0kwTUE0RwpBMVVkRHdFQi93UUVBd0lIZ0RBVEJnTlZIU1VFRERBS0JnZ3JCZ0VGQlFjREF6QWRCZ05WSFE0RUZnUVVPOERSCjBzaTZMVldWSDJoNDNNWXMyYlVYRHVvd0h3WURWUjBqQkJnd0ZvQVUzOVBwejFZa0VaYjVxTmpwS0ZXaXhpNFkKWkQ4d1lRWURWUjBSQVFIL0JGY3dWWVpUYUhSMGNITTZMeTluYVhSb2RXSXVZMjl0TDJOaFpHUjVjMlZ5ZG1BeS16TG1kcGRHaDEKWW5WelpYSmpiMjUwWlc1MExtTnZiVEFTQmdvckJnRUVBWU8vTUFFQ0JBUndkWE5vTURZR0Npc0dBUVFCZzc4dwpBUU1FS0RneU1XRXdPR0UyWlRNNVpXUXdaVGRqTkROaU1ESTNNV05qWmpFeU5tTXhPVFJsWWpZek16a3dGUVlLCkt3WUJCQUdEdnpBQkJBUUhVbVZzWldGelpUQWZCZ29yQmdFRUFZTy9NQUVGQkJGallXUmtlWE5sY25abGNpOWoKWVdSa2VUQWVCZ29yQmdFRUFZTy9NQUVHQkJCeVpXWnpMM1JoWjNNdmRqSXVOaTR3TUlHS0Jnb3JCZ0VFQWRaNQpBZ1FDQkh3RWVnQjRBSFlBQ0dDUzhDaFMvMmhGMGRGcko0U2NSV2NZckJZOXd6alNiZWE4SWdZMmIzSUFBQUdEClcrZEVVd0FBQkFNQVJ6QkZBaUVBbkQ1TlJLWmhGTGhDSEhESXpWNmJ3VkFxbFlQNmRXMEN3S1dEbzFqem1FWUMKSUU1WmVlSzE0b2k2SSs3ejJWUlhTVnE0L3IxNUdBRnhZYUNNRnJJMFVPampNQW9HQ0NxR1NNNDlCQU1EQTJrQQpNR1lDTVFDK3N6d1ZWbmhreGcrOFNHbXBDaWZOVFpJNUFGQkNxQ3F0RVUxazhtRTE3QWpwdFdvVUcvYkJEa2J1Cm9GUUlKdUVDTVFDbmJaZmJUTWpkUnhNOUtIcW04MlJRTEZxZG5SRFF6Mi9RNlRkMi9jeU9uY05ydW5nSFFHcEEKMXR2Mmw5VnFOcDA9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K" } } } }, "LogIndex": 3618623, "IntegratedTime": 1663694226, "UUID": "04deb84e5a73ba75ea69092c6d700eaeb869c29cae3e0cf98dbfef871361ed09", "LogID": "c0d23d6ad406973f9559f3ba2d1ca01f84147d8ffc5b8445c224f98b9591801d" } ``` 我們現在知道成品已簽名,且其簽名已記錄在 Rekor 透明度日誌伺服器上。下一步是驗證簽名和成品是否是 Caddy 專案 CI/CD 工作流的產物。我們透過從查詢 Rekor 接收到的 JSON 中提取公鑰,將其 base64 解碼為 PEM 檔案,然後使用 `openssl` 檢查憑證來完成此操作。執行以下命令從我們之前收到的 Rekor 回應中提取憑證,對其進行 base64 解碼,並將結果儲存在檔案中。 rekor-cli get --uuid $(rekor-cli search --artifact ./caddy_2.6.0_checksums.txt --format json | jq -r '.UUIDs[0]') --format json | jq -r '.Body.HashedRekordObj.signature.publicKey.content' | base64 -d > cert.pem 現在使用 openssl 檢查憑證並注意 X509v3 extensions 部分。 openssl x509 -in cert.pem -text Certificate: ... Issuer: O=sigstore.dev, CN=sigstore-intermediate ... X509v3 extensions: X509v3 Key Usage: critical Digital Signature X509v3 Extended Key Usage: Code Signing X509v3 Subject Key Identifier: 3B:C0:D1:D2:C8:BA:2D:55:95:1F:68:78:DC:C6:2C:D9:B5:17:0E:EA X509v3 Authority Key Identifier: keyid:DF:D3:E9:CF:56:24:11:96:F9:A8:D8:E9:28:55:A2:C6:2E:18:64:3F X509v3 Subject Alternative Name: critical URI:https://github.com/caddyserver/caddy/.github/workflows/release.yml@refs/tags/v2.6.0 1.3.6.1.4.1.57264.1.1: https://token.actions.githubusercontent.com 1.3.6.1.4.1.57264.1.2: push 1.3.6.1.4.1.57264.1.3: 821a08a6e39ed0e7c43b0271ccf126c194eb6339 1.3.6.1.4.1.57264.1.4: Release 1.3.6.1.4.1.57264.1.5: caddyserver/caddy 1.3.6.1.4.1.57264.1.6: refs/tags/v2.6.0 1.3.6.1.4.1.11129.2.4.2: .z.x.v..`..(R.hE..k'..Eg...=.8.m..".6or....[.DS.....G0E.!..>MD.a..B.p..^..P*...um.....X..F. NYy.....#...TWIZ...y..qa....4P.. ... 擴展值 (extensions values) 表示成品的真實性。有關各個擴展的定義,請參閱 Sigstore OID 資訊。 如果簽名未通過驗證怎麼辦? 簽名驗證失敗表示手頭的成品不是由 GitHub 上 Caddy 專案的 CI/CD 工作流產生的。如果您有簽名、憑證和成品,那麼您正在尋找 cosign 報告的成功驗證。或者,您可以使用 rekor-cli 檢查 Rekor 伺服器中的條目,驗證憑證擴展是否具有正確且預期的值,並匹配校驗和與簽名。Rekor 條目不匹配或缺失意味著成品不是由 Caddy 專案的 CI/CD 產生的,或者成品在 CI/CD 建構流程、GitHub 發佈頁面和交付給您的過程中某處被篡改。