Skip to content

Commit

Permalink
Support verifying digests in addition to artifacts
Browse files Browse the repository at this point in the history
Signed-off-by: Facundo Tuesca <[email protected]>
  • Loading branch information
facutuesca committed Sep 18, 2024
1 parent bcbeee6 commit dee7a56
Show file tree
Hide file tree
Showing 8 changed files with 135 additions and 74 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/conformance.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:
cache: "pip"

- name: install sigstore-python
run: pip install "sigstore ~= 3.0"
run: pip install "sigstore >= 3.3.0, < 4.0"

- name: conformance test sigstore-python
uses: ./
Expand Down
5 changes: 3 additions & 2 deletions docs/cli_protocol.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ ${ENTRYPOINT} verify [--staging] --signature FILE --certificate FILE --certifica
#### Bundle flow

```console
${ENTRYPOINT} verify-bundle [--staging] --bundle FILE --certificate-identity IDENTITY --certificate-oidc-issuer URL [--trusted-root FILE] FILE
${ENTRYPOINT} verify-bundle [--staging] --bundle FILE --certificate-identity IDENTITY --certificate-oidc-issuer URL [--trusted-root FILE] [--verify-digest] FILE_OR_DIGEST
```

| Option | Description |
Expand All @@ -87,4 +87,5 @@ ${ENTRYPOINT} verify-bundle [--staging] --bundle FILE --certificate-identity IDE
| `--certificate-identity IDENTITY` | The expected identity in the signing certificate's SAN extension |
| `--certificate-oidc-issuer URL` | The expected OIDC issuer for the signing certificate |
| `--trusted-root` | The path of the custom trusted root to use to verify the bundle |
| `FILE` | The path to the artifact to verify |
| `--verify-digest` | Presence indicates client should interpret `FILE_OR_DIGEST` as a digest. |
| `FILE_OR_DIGEST` | The path to the artifact to verify, or its digest. The digest should start with the `sha256:` prefix. |
4 changes: 4 additions & 0 deletions sigstore-python-conformance
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ SUBCMD_REPLACEMENTS = {
ARG_REPLACEMENTS = {
"--certificate-identity": "--cert-identity",
"--certificate-oidc-issuer": "--cert-oidc-issuer",
# sigstore-python detects if the input is a file path or a digest without needing a flag
"--verify-digest": None,
}

# Trim the script name.
Expand Down Expand Up @@ -43,5 +45,7 @@ else:

# Replace incompatible flags.
command.extend(ARG_REPLACEMENTS[arg] if arg in ARG_REPLACEMENTS else arg for arg in fixed_args)
# Remove unneeded flags
command = [arg for arg in command if arg is not None]

os.execvp("sigstore", command)
40 changes: 35 additions & 5 deletions test/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -225,13 +225,13 @@ def _sign_for_bundle(self, materials: BundleMaterials, artifact: os.PathLike) ->
self.run(*args)

@singledispatchmethod
def verify(self, materials: VerificationMaterials, artifact: os.PathLike) -> None:
def verify(self, materials: VerificationMaterials, artifact: os.PathLike | str) -> None:
"""
Verify an artifact with the Sigstore client. Dispatches to `_verify_for_sigcrt`
when given `SignatureCertificateMaterials`, or `_verify_for_bundle` when given
`BundleMaterials`.
when given `SignatureCertificateMaterials`, or
`_verify_{artifact|digest}_for_bundle` when given `BundleMaterials`.
`artifact` is the path to the file to verify.
`artifact` is the path to the file to verify, or its digest.
`materials` contains paths to the materials to verify with.
"""

Expand Down Expand Up @@ -272,7 +272,9 @@ def _verify_for_sigcrt(
self.run(*args, artifact)

@verify.register
def _verify_for_bundle(self, materials: BundleMaterials, artifact: os.PathLike) -> None:
def _verify_artifact_for_bundle(
self, materials: BundleMaterials, artifact: os.PathLike
) -> None:
"""
Verify an artifact given a bundle with the Sigstore client.
Expand All @@ -297,3 +299,31 @@ def _verify_for_bundle(self, materials: BundleMaterials, artifact: os.PathLike)
args.extend(["--trusted-root", materials.trusted_root])

self.run(*args, artifact)

@verify.register
def _verify_digest_for_bundle(self, materials: BundleMaterials, digest: str) -> None:
"""
Verify a digest given a bundle with the Sigstore client.
This is an overload of `verify` for the bundle flow and should not be called
directly. The digest string is expected to start with the `sha256:` prefix.
"""
args: list[str | os.PathLike] = ["verify-bundle"]
if self.staging:
args.append("--staging")
args.extend(
[
"--bundle",
materials.bundle,
"--certificate-identity",
CERTIFICATE_IDENTITY,
"--certificate-oidc-issuer",
CERTIFICATE_OIDC_ISSUER,
"--verify-digest",
]
)

if getattr(materials, "trusted_root", None) is not None:
args.extend(["--trusted-root", materials.trusted_root])

self.run(*args, digest)
12 changes: 8 additions & 4 deletions test/conftest.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import functools
import hashlib
import json
import os
import shutil
Expand All @@ -22,8 +23,8 @@
)

_M = TypeVar("_M", bound=VerificationMaterials)
_MakeMaterialsByType = Callable[[str, _M], tuple[Path, _M]]
_MakeMaterials = Callable[[str], tuple[Path, VerificationMaterials]]
_MakeMaterialsByType = Callable[[str, _M], tuple[Path, str, _M]]
_MakeMaterials = Callable[[str], tuple[Path, str, VerificationMaterials]]

_OIDC_BEACON_API_URL = (
"https://api.github.com/repos/sigstore-conformance/extremely-dangerous-public-oidc-beacon/"
Expand Down Expand Up @@ -178,11 +179,14 @@ def make_materials_by_type() -> _MakeMaterialsByType:

def _make_materials_by_type(
input_name: str, cls: VerificationMaterials
) -> tuple[Path, VerificationMaterials]:
) -> tuple[Path, str, VerificationMaterials]:
input_path = Path(input_name)
output = cls.from_input(input_path)

return (input_path, output)
with open(input_path, "rb") as f:
digest = f"sha256:{hashlib.sha256(f.read()).hexdigest()}"

return (input_path, digest, output)

return _make_materials_by_type

Expand Down
Loading

0 comments on commit dee7a56

Please sign in to comment.