{"id":50830715,"url":"https://github.com/shiftleftcyber/securesbom-verifier","last_synced_at":"2026-06-13T22:32:29.624Z","repository":{"id":352981641,"uuid":"1215903400","full_name":"shiftleftcyber/securesbom-verifier","owner":"shiftleftcyber","description":"Verification library and offline CLI for signed SBOMs and digest signatures.","archived":false,"fork":false,"pushed_at":"2026-04-29T00:48:15.000Z","size":72,"stargazers_count":1,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-29T02:34:24.091Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/shiftleftcyber.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-20T11:17:34.000Z","updated_at":"2026-04-29T00:48:12.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/shiftleftcyber/securesbom-verifier","commit_stats":null,"previous_names":["shiftleftcyber/securesbom-verifier"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/shiftleftcyber/securesbom-verifier","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shiftleftcyber%2Fsecuresbom-verifier","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shiftleftcyber%2Fsecuresbom-verifier/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shiftleftcyber%2Fsecuresbom-verifier/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shiftleftcyber%2Fsecuresbom-verifier/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/shiftleftcyber","download_url":"https://codeload.github.com/shiftleftcyber/securesbom-verifier/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shiftleftcyber%2Fsecuresbom-verifier/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34303280,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-13T02:00:06.617Z","response_time":62,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-06-13T22:32:29.113Z","updated_at":"2026-06-13T22:32:29.619Z","avatar_url":"https://github.com/shiftleftcyber.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Secure SBOM Verifier\n\n`securesbom-verifier` is a Go library for verifying signed SBOMs and signed\ndigests with public keys. It is designed to be reused by:\n\n- API servers that need SBOM verification business logic\n- offline or air-gapped verification workflows\n- other Go services that need digest signature verification\n- command-line tooling that wants to wrap the same library behavior\n\n## What This Project Contains\n\n- CycloneDX embedded signature verification\n- AI-BOM embedded signature verification\n- SPDX detached signature verification\n- digest signature verification\n- JSON canonicalization helpers used during verification\n- PEM normalization and key utility helpers\n- an optional offline verification CLI\n- tests for the lower-level verification building blocks\n\n## Verification-Only Scope\n\nThis module intentionally excludes:\n\n- key generation\n- signing\n- private-key verification helpers\n- key store backends\n\nThe only cryptographic operations here are verification using a public key.\n\n## Quick Start\n\n```bash\nmake test\nmake build-cli\n```\n\n## Library Usage\n\nImport the module root directly:\n\n```go\nimport securesbomverifier \"github.com/shiftleftcyber/securesbom-verifier\"\n```\n\nFor CycloneDX embedded signatures:\n\n```go\nverifier := securesbomverifier.NewVerifier()\n\nresult, err := verifier.VerifyCycloneDXEmbeddedVersioned(\n  signedSBOM,\n  string(publicKeyPEM),\n  securesbomverifier.VerificationV2,\n)\n```\n\nWhen key metadata is available, use the key-based root API:\n\n```go\nresult, err := verifier.VerifyCycloneDXEmbeddedWithKeyVersioned(\n  signedSBOM,\n  securesbomverifier.VerificationKey{\n    KeyID:     \"production-key-2026-04\",\n    Algorithm: \"ES256\",\n    PublicKey: string(publicKeyPEM),\n  },\n  securesbomverifier.VerificationV2,\n)\n```\n\nFor AI-BOM embedded signatures:\n\n```go\nverifier := securesbomverifier.NewVerifier()\n\nresult, err := verifier.VerifyAIBOMEmbeddedVersioned(\n  signedAIBOM,\n  string(publicKeyPEM),\n  securesbomverifier.VerificationV2,\n)\n```\n\nAI-BOM verification is supported only with `VerificationV2`.\n\nWhen key metadata is available, use the key-based root API:\n\n```go\nresult, err := verifier.VerifyAIBOMEmbeddedWithKeyVersioned(\n  signedAIBOM,\n  securesbomverifier.VerificationKey{\n    KeyID:     \"production-ai-bom-key-2026-05\",\n    Algorithm: \"ES256\",\n    PublicKey: string(publicKeyPEM),\n  },\n  securesbomverifier.VerificationV2,\n)\n```\n\nFor SPDX detached signatures:\n\n```go\nverifier := securesbomverifier.NewVerifier()\n\nresult, err := verifier.VerifySPDXDetachedVersioned(\n  spdxSBOM,\n  signatureB64,\n  string(publicKeyPEM),\n  securesbomverifier.VerificationV2,\n)\nif err != nil {\n  if errors.Is(err, securesbomverifier.ErrSignatureFail) {\n    // Signature did not verify.\n  }\n}\n```\n\nFor digest verification:\n\n```go\nimport (\n  \"errors\"\n\n  securesbomverifier \"github.com/shiftleftcyber/securesbom-verifier\"\n)\n\nverifier := securesbomverifier.NewVerifier()\n\nresult, err := verifier.VerifyDigest(\n  securesbomverifier.VerifyDigestInput{\n    KeyID:         \"production-key-2026-04\",\n    HashAlgorithm: \"sha256\",\n    Digest:        digestB64,\n    Signature:     signatureB64,\n  },\n  securesbomverifier.VerificationKey{\n    KeyID:     \"production-key-2026-04\",\n    Algorithm: \"ES256\",\n    PublicKey: string(publicKeyPEM),\n  },\n)\nif err != nil {\n  switch {\n  case errors.Is(err, securesbomverifier.ErrInvalidDigest),\n    errors.Is(err, securesbomverifier.ErrInvalidSignature),\n    errors.Is(err, securesbomverifier.ErrInvalidHashAlgorithm),\n    errors.Is(err, securesbomverifier.ErrInvalidKeyID),\n    errors.Is(err, securesbomverifier.ErrInvalidKey):\n    // Bad request or bad key metadata.\n  case errors.Is(err, securesbomverifier.ErrVerificationFailed):\n    // Well-formed input, but the signature did not verify.\n  default:\n    // Unexpected operational failure.\n  }\n  return err\n}\n_ = result.Verified\n```\n\nThe lower-level packages remain available for advanced integrations:\n\n```go\nimport (\n  digestsigning \"github.com/shiftleftcyber/securesbom-verifier/services/digest\"\n  \"github.com/shiftleftcyber/securesbom-verifier/verificationkey\"\n)\n```\n\n## Digest Verification\n\n`VerifyDigest` verifies an ASN.1 DER ECDSA signature over a digest that was\ncomputed by the caller.\n\nRequest fields:\n\n- `KeyID`: required key identifier. It must match `VerificationKey.KeyID` when\n  the key metadata includes one.\n- `HashAlgorithm`: required digest algorithm. Currently only `sha256` is\n  supported.\n- `Digest`: required standard-base64 encoding of the raw digest bytes. For\n  `sha256`, this must decode to exactly 32 bytes.\n- `Signature`: required standard-base64 encoding of the ASN.1 DER ECDSA\n  signature bytes.\n\nKey metadata uses the same root type for digest and SBOM integrations:\n\n```go\ntype VerificationKey struct {\n  KeyID     string\n  Algorithm string\n  PublicKey string\n}\n```\n\n`Algorithm` is the signing key algorithm. Digest verification accepts ECDSA\nalgorithm labels `ES256`, `ES384`, and `ES512`; current digest hashing is\n`sha256`.\n\n## Stable Errors\n\nThe root package exports stable errors for mapping verification results to API\nresponses. Use `errors.Is` because errors may include additional context.\n\n- Bad input or bad metadata: `ErrInvalidSBOM`, `ErrMissingSignature`,\n  `ErrInvalidHashAlgorithm`, `ErrInvalidDigest`, `ErrInvalidKeyID`,\n  `ErrInvalidSignature`, `ErrInvalidKey`, `ErrKeyNotFound`.\n- Cryptographic verification failure: `ErrSignatureFail` for SBOM signatures and\n  `ErrVerificationFailed` for digest signatures.\n\nFor HTTP APIs, bad input generally maps to `400 Bad Request`, missing keys to\n`404 Not Found`, and cryptographic verification failures to `422 Unprocessable\nEntity` or a domain-specific verification-failed response.\n\n## Versioned Verification Semantics\n\nUse `VerificationV2` for new integrations.\n\n- `VerificationV1` preserves the original canonicalization behavior used by the\n  source service. It is useful when verifying signatures produced by older\n  signing flows.\n- `VerificationV2` uses the newer canonicalization behavior and is the default\n  recommendation for new signatures, including AI-BOM embedded signatures.\n\nAI-BOM embedded verification is only available with `VerificationV2`; the V1\nverification behavior remains limited to the existing CycloneDX and SPDX flows.\n\nMigration note: keep verifying historical artifacts with the version used when\nthey were signed. Sign new CycloneDX embedded, AI-BOM embedded, and SPDX\ndetached artifacts with `VerificationV2`, then update callers to pass\n`securesbomverifier.VerificationV2`.\n\n```go\n_, err = verifier.VerifyCycloneDXEmbeddedVersioned(signedSBOM, publicKeyPEM, securesbomverifier.VerificationV1)\n_, err = verifier.VerifyCycloneDXEmbeddedVersioned(signedSBOM, publicKeyPEM, securesbomverifier.VerificationV2)\n_, err = verifier.VerifyAIBOMEmbeddedVersioned(signedAIBOM, publicKeyPEM, securesbomverifier.VerificationV2)\n_, err = verifier.VerifySPDXDetachedVersioned(spdxSBOM, signatureB64, publicKeyPEM, securesbomverifier.VerificationV1)\n_, err = verifier.VerifySPDXDetachedVersioned(spdxSBOM, signatureB64, publicKeyPEM, securesbomverifier.VerificationV2)\n```\n\n## Production Integration Example\n\nSee [examples/production-api/main.go](examples/production-api/main.go) for an\nHTTP-style integration that fetches public key metadata, verifies CycloneDX,\nSPDX detached, and digest requests, handles stable errors, and maps them to\nresponses.\n\n## Contract Fixtures\n\nThe `testsupport` package provides reusable fixtures for downstream service\ntests:\n\n```go\nfixtures := testsupport.NewContractFixtures(t)\n```\n\nThe fixture set includes valid and invalid CycloneDX embedded signatures,\nAI-BOM embedded signatures, SPDX detached signatures, and digest signatures,\nalong with public keys and expected verification outcomes.\n\n## Build Note\n\nThis project currently relies on `GOEXPERIMENT=jsonv2`, matching the behavior\nalready used by the source repository. The included `Makefile` sets that for the\ncommon build and test flows.\n\n## Container Image\n\nBuild the offline verification CLI as a container:\n\n```bash\nmake docker-build\n```\n\nRun it locally:\n\n```bash\ndocker run --rm \\\n  -v \"$PWD:/work\" \\\n  secure-sbom-verification-cli:dev \\\n  --sbom /work/path/to/signed-sbom.json \\\n  --pubkey /work/path/to/public.pem\n```\n\n## Optional CLI\n\nThe offline CLI is an optional command. Library consumers do not need to import\nor build it. It lives at:\n\n```text\ncmd/sbom-offline-verification\n```\n\nExample:\n\n```bash\nGOEXPERIMENT=jsonv2 go run ./cmd/sbom-offline-verification \\\n  --sbom ./path/to/signed-sbom.json \\\n  --pubkey ./path/to/public.pem\n```\n\nThe same command verifies signed CycloneDX or signed AI-BOM files. The verifier\ndetects AI-BOM files as `AI-SBOM` and verifies the embedded\n`metadata.sbomAuthorSignature` value with the supplied public key.\n\nFor detached SPDX verification:\n\n```bash\nGOEXPERIMENT=jsonv2 go run ./cmd/sbom-offline-verification \\\n  --sbom ./path/to/sample.spdx.json \\\n  --signature BASE64_SIGNATURE \\\n  --pubkey ./path/to/public.pem \\\n  --verification-version v2\n```\n\nFor digest verification:\n\n```bash\nGOEXPERIMENT=jsonv2 go run ./cmd/sbom-offline-verification \\\n  --digest BASE64_DIGEST \\\n  --signature BASE64_SIGNATURE \\\n  --pubkey ./path/to/public.pem \\\n  --hash-algorithm sha256 \\\n  --signature-algorithm ES256\n```\n\n## Releases\n\nTagged releases matching `vX.X.X` are built with Goreleaser using\n[.goreleaser.yml](.goreleaser.yml). The release workflow publishes multi-platform\nCLI archives, a checksum file, and a container image to GitHub-hosted release\nsurfaces. The container image is published to GitHub Container Registry as\n`ghcr.io/\u003cowner\u003e/\u003crepo\u003e` for `linux/amd64` and `linux/arm64`, with tags for the\nfull version, `vMAJOR.MINOR`, `vMAJOR`, and `latest`.\n\n## Examples\n\nSee [examples/library/main.go](examples/library/main.go) for a minimal embedding\nexample for CycloneDX verification, [examples/spdx-detached/main.go](examples/spdx-detached/main.go)\nfor SPDX detached verification, [examples/digest/main.go](examples/digest/main.go)\nfor digest verification, and [MIGRATION.md](MIGRATION.md) for a suggested next-step\nextraction plan from `sbom-signing-api`.\n\nThe example programs expect you to provide signed content, signatures, and/or a\npublic key path at runtime depending on the verification mode.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshiftleftcyber%2Fsecuresbom-verifier","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fshiftleftcyber%2Fsecuresbom-verifier","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshiftleftcyber%2Fsecuresbom-verifier/lists"}