Skip to content

Commit 6022734

Browse files
authored
chore: refactor - expose only what is needed (#5)
1 parent 8e0b93c commit 6022734

7 files changed

Lines changed: 241 additions & 10 deletions

File tree

Makefile

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@ BINARY_NAME ?= sbom-offline-verification
22
GOCACHE ?= $(CURDIR)/.gocache
33
GOMODCACHE ?= $(GOCACHE)/pkg/mod
44
GOEXPERIMENT ?= jsonv2
5-
GOFILES := $(shell find . -name "*.go")
5+
GOFILES := $(shell find . \( -path './.git' -o -path './.gocache' -o -path './dist' -o -path './vendor' \) -prune -o -type f -name "*.go" -print)
66
GOFMT ?= gofmt "-s"
77
DIST_DIR ?= dist
88
IMAGE_NAME ?= secure-sbom-verification-cli
99
IMAGE_TAG ?= dev
1010
GOVULNCHECK_SCAN ?= package
11+
GOLANGCI_LINT ?= golangci-lint
1112

1213
.PHONY: test coverage build-cli docker-build tidy vulncheck goreleaser-dryrun clean
1314

@@ -58,4 +59,4 @@ fmt-check:
5859

5960
.PHONY: lint
6061
lint:
61-
@DOCKER run --rm -v $(shell pwd):/app -w /app --env GOEXPERIMENT=jsonv2 golangci/golangci-lint:v2.8.0-alpine golangci-lint run ./...
62+
@docker run --rm -v $(shell pwd):/app -w /app --env GOEXPERIMENT=jsonv2 golangci/golangci-lint:v2.8.0-alpine $(GOLANGCI_LINT) run ./...

README.md

Lines changed: 76 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,76 @@ make test
4040
make build-cli
4141
```
4242

43+
## Library Usage
44+
45+
Import the module root directly:
46+
47+
```go
48+
import securesbomverifier "github.com/shiftleftcyber/securesbom-verifier"
49+
```
50+
51+
For CycloneDX embedded signatures:
52+
53+
```go
54+
verifier := securesbomverifier.NewVerifier()
55+
56+
result, err := verifier.VerifyCycloneDXEmbeddedVersioned(
57+
signedSBOM,
58+
string(publicKeyPEM),
59+
securesbomverifier.VerificationV2,
60+
)
61+
```
62+
63+
For SPDX detached signatures:
64+
65+
```go
66+
verifier := securesbomverifier.NewVerifier()
67+
68+
result, err := verifier.VerifySPDXDetachedVersioned(
69+
spdxSBOM,
70+
signatureB64,
71+
string(publicKeyPEM),
72+
securesbomverifier.VerificationV2,
73+
)
74+
if err != nil {
75+
if errors.Is(err, securesbomverifier.ErrSignatureFail) {
76+
// Signature did not verify.
77+
}
78+
}
79+
```
80+
81+
For digest verification, the current library API is exposed through the lower-level
82+
`services/digest` package rather than the root wrapper:
83+
84+
```go
85+
import (
86+
digestsigning "github.com/shiftleftcyber/securesbom-verifier/services/digest"
87+
"github.com/shiftleftcyber/securesbom-verifier/verificationkey"
88+
)
89+
90+
validated, err := digestsigning.NewValidator().ValidateVerifyDigestRequest(
91+
digestsigning.VerifyDigestInput{
92+
KeyID: "offline",
93+
HashAlgorithm: "sha256",
94+
Digest: digestB64,
95+
Signature: signatureB64,
96+
},
97+
)
98+
if err != nil {
99+
return err
100+
}
101+
102+
err = digestsigning.NewCryptoVerifier().Verify(
103+
&verificationkey.KeyInfo{
104+
KeyID: "offline",
105+
Algorithm: "ES256",
106+
PublicKey: string(publicKeyPEM),
107+
},
108+
validated.Digest,
109+
validated.Signature,
110+
)
111+
```
112+
43113
## Build Note
44114

45115
This project currently relies on `GOEXPERIMENT=jsonv2`, matching the behavior
@@ -110,8 +180,10 @@ CLI archives and a checksum file to the GitHub release.
110180
## Examples
111181

112182
See [examples/library/main.go](examples/library/main.go) for a minimal embedding
113-
example from another Go service, and [MIGRATION.md](MIGRATION.md) for a suggested
114-
next-step extraction plan from `sbom-signing-api`.
183+
example for CycloneDX verification, [examples/spdx-detached/main.go](examples/spdx-detached/main.go)
184+
for SPDX detached verification, [examples/digest/main.go](examples/digest/main.go)
185+
for digest verification, and [MIGRATION.md](MIGRATION.md) for a suggested next-step
186+
extraction plan from `sbom-signing-api`.
115187

116-
The example program expects you to provide a signed SBOM path and a public key
117-
path at runtime.
188+
The example programs expect you to provide signed content, signatures, and/or a
189+
public key path at runtime depending on the verification mode.

examples/digest/main.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"log"
6+
"os"
7+
8+
digestsigning "github.com/shiftleftcyber/securesbom-verifier/services/digest"
9+
"github.com/shiftleftcyber/securesbom-verifier/verificationkey"
10+
)
11+
12+
func main() {
13+
if len(os.Args) != 4 {
14+
log.Fatalf("usage: %s <digest-base64> <signature-base64> <public-key-path>", os.Args[0])
15+
}
16+
17+
if err := verifyDigestExample(os.Args[1], os.Args[2], os.Args[3]); err != nil {
18+
log.Fatal(err)
19+
}
20+
21+
fmt.Println("verification result: signature is valid")
22+
}
23+
24+
func verifyDigestExample(digestB64, signatureB64, publicKeyPath string) error {
25+
pub, err := os.ReadFile(publicKeyPath)
26+
if err != nil {
27+
return fmt.Errorf("read public key: %w", err)
28+
}
29+
30+
validated, err := digestsigning.NewValidator().ValidateVerifyDigestRequest(digestsigning.VerifyDigestInput{
31+
KeyID: "offline",
32+
HashAlgorithm: "sha256",
33+
Digest: digestB64,
34+
Signature: signatureB64,
35+
})
36+
if err != nil {
37+
return fmt.Errorf("validate digest request: %w", err)
38+
}
39+
40+
err = digestsigning.NewCryptoVerifier().Verify(
41+
&verificationkey.KeyInfo{
42+
KeyID: "offline",
43+
Algorithm: "ES256",
44+
PublicKey: string(pub),
45+
},
46+
validated.Digest,
47+
validated.Signature,
48+
)
49+
if err != nil {
50+
return fmt.Errorf("verify digest: %w", err)
51+
}
52+
53+
return nil
54+
}

examples/library/main.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import (
55
"log"
66
"os"
77

8-
"github.com/shiftleftcyber/securesbom-verifier/application"
8+
securesbomverifier "github.com/shiftleftcyber/securesbom-verifier"
99
)
1010

1111
func main() {
@@ -21,7 +21,7 @@ func main() {
2121
fmt.Printf("verification result: %+v\n", result)
2222
}
2323

24-
func verifyExample(sbomPath, publicKeyPath string) (*application.VerificationResult, error) {
24+
func verifyExample(sbomPath, publicKeyPath string) (*securesbomverifier.VerificationResult, error) {
2525
sbom, err := os.ReadFile(sbomPath)
2626
if err != nil {
2727
return nil, fmt.Errorf("read sbom: %w", err)
@@ -32,8 +32,8 @@ func verifyExample(sbomPath, publicKeyPath string) (*application.VerificationRes
3232
return nil, fmt.Errorf("read public key: %w", err)
3333
}
3434

35-
app := application.NewVerifierApp()
36-
result, err := app.VerifyCycloneDXEmbeddedVersioned(sbom, string(pub), application.VerificationV2)
35+
verifier := securesbomverifier.NewVerifier()
36+
result, err := verifier.VerifyCycloneDXEmbeddedVersioned(sbom, string(pub), securesbomverifier.VerificationV2)
3737
if err != nil {
3838
return nil, fmt.Errorf("verify: %w", err)
3939
}

examples/spdx-detached/main.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"log"
6+
"os"
7+
8+
securesbomverifier "github.com/shiftleftcyber/securesbom-verifier"
9+
)
10+
11+
func main() {
12+
if len(os.Args) != 4 {
13+
log.Fatalf("usage: %s <spdx-sbom-path> <signature> <public-key-path>", os.Args[0])
14+
}
15+
16+
result, err := verifySPDXExample(os.Args[1], os.Args[2], os.Args[3])
17+
if err != nil {
18+
log.Fatal(err)
19+
}
20+
21+
fmt.Printf("verification result: %+v\n", result)
22+
}
23+
24+
func verifySPDXExample(sbomPath, signatureB64, publicKeyPath string) (*securesbomverifier.VerificationResult, error) {
25+
sbom, err := os.ReadFile(sbomPath)
26+
if err != nil {
27+
return nil, fmt.Errorf("read SBOM: %w", err)
28+
}
29+
30+
pub, err := os.ReadFile(publicKeyPath)
31+
if err != nil {
32+
return nil, fmt.Errorf("read public key: %w", err)
33+
}
34+
35+
verifier := securesbomverifier.NewVerifier()
36+
result, err := verifier.VerifySPDXDetachedVersioned(sbom, signatureB64, string(pub), securesbomverifier.VerificationV2)
37+
if err != nil {
38+
return nil, fmt.Errorf("verify SPDX: %w", err)
39+
}
40+
41+
return result, nil
42+
}

securesbom_verifier.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package securesbomverifier
2+
3+
import "github.com/shiftleftcyber/securesbom-verifier/application"
4+
5+
type VerificationResult = application.VerificationResult
6+
7+
type VerificationVersion = application.VerificationVersion
8+
9+
const (
10+
VerificationV1 = application.VerificationV1
11+
VerificationV2 = application.VerificationV2
12+
)
13+
14+
var (
15+
ErrSignatureFail = application.ErrSignatureFail
16+
)
17+
18+
type Verifier struct {
19+
app *application.VerifierApp
20+
}
21+
22+
func NewVerifier() *Verifier {
23+
return &Verifier{
24+
app: application.NewVerifierApp(),
25+
}
26+
}
27+
28+
func (v *Verifier) VerifyCycloneDXEmbeddedVersioned(
29+
signedSBOM []byte,
30+
publicKeyPEM string,
31+
version VerificationVersion,
32+
) (*VerificationResult, error) {
33+
return v.app.VerifyCycloneDXEmbeddedVersioned(signedSBOM, publicKeyPEM, version)
34+
}
35+
36+
func (v *Verifier) VerifySPDXDetachedVersioned(
37+
sbom []byte,
38+
signatureB64 string,
39+
publicKeyPEM string,
40+
version VerificationVersion,
41+
) (*VerificationResult, error) {
42+
return v.app.VerifySPDXDetachedVersioned(sbom, signatureB64, publicKeyPEM, version)
43+
}

securesbom_verifier_test.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package securesbomverifier
2+
3+
import (
4+
"testing"
5+
6+
"github.com/shiftleftcyber/securesbom-verifier/testsupport"
7+
)
8+
9+
func TestNewVerifier_RootPackageAPI(t *testing.T) {
10+
signed, publicKey := testsupport.SignedCycloneDXV2(t, "ES256")
11+
12+
result, err := NewVerifier().VerifyCycloneDXEmbeddedVersioned(signed, publicKey, VerificationV2)
13+
if err != nil {
14+
t.Fatalf("expected no error, got %v", err)
15+
}
16+
if result.Message != "signature is valid" {
17+
t.Fatalf("unexpected message: %s", result.Message)
18+
}
19+
}

0 commit comments

Comments
 (0)