diff --git a/pkg/digest/digest.go b/pkg/digest/digest.go index 99be6f8c608..5d9fa2ef1c6 100644 --- a/pkg/digest/digest.go +++ b/pkg/digest/digest.go @@ -21,6 +21,7 @@ func (a Algorithm) String() string { const ( SHA1 Algorithm = "sha1" // sha1 with hex encoding (lower case only) SHA256 Algorithm = "sha256" // sha256 with hex encoding (lower case only) + MD5 Algorithm = "md5" // md5 with hex encoding (lower case only) ) // Digest allows simple protection of hex formatted digest strings, prefixed by their algorithm. @@ -35,6 +36,11 @@ func NewDigest(alg Algorithm, h hash.Hash) Digest { return Digest(fmt.Sprintf("%s:%x", alg, h.Sum(nil))) } +// NewDigestFromString returns a Digest from alg and a string. +func NewDigestFromString(alg Algorithm, h string) Digest { + return Digest(fmt.Sprintf("%s:%s", alg, h)) +} + func (d Digest) Algorithm() Algorithm { return Algorithm(d[:d.sepIndex()]) } diff --git a/pkg/fanal/analyzer/analyzer_test.go b/pkg/fanal/analyzer/analyzer_test.go index abc7a41f6f5..fec8761c7da 100644 --- a/pkg/fanal/analyzer/analyzer_test.go +++ b/pkg/fanal/analyzer/analyzer_test.go @@ -344,6 +344,7 @@ func TestAnalyzerGroup_AnalyzeFile(t *testing.T) { SrcName: "musl", SrcVersion: "1.1.24-r2", Licenses: []string{"MIT"}, + Digest: "sha1:cb2316a189ebee5282c4a9bd98794cc2477a74c6", }, }, }, diff --git a/pkg/fanal/analyzer/pkg/apk/apk.go b/pkg/fanal/analyzer/pkg/apk/apk.go index 57aa3a8b426..48895a6d6ce 100644 --- a/pkg/fanal/analyzer/pkg/apk/apk.go +++ b/pkg/fanal/analyzer/pkg/apk/apk.go @@ -3,6 +3,8 @@ package apk import ( "bufio" "context" + "encoding/base64" + "encoding/hex" "fmt" "os" "path" @@ -13,6 +15,7 @@ import ( "github.com/samber/lo" "golang.org/x/exp/slices" + "github.com/aquasecurity/trivy/pkg/digest" "github.com/aquasecurity/trivy/pkg/fanal/analyzer" "github.com/aquasecurity/trivy/pkg/fanal/types" "github.com/aquasecurity/trivy/pkg/licensing" @@ -91,6 +94,11 @@ func (a alpinePkgAnalyzer) parseApkInfo(scanner *bufio.Scanner) ([]types.Package a.parseProvides(line, pkg.ID, provides) case "D:": // dependencies (corresponds to depend in PKGINFO, concatenated by spaces into a single line) pkg.DependsOn = a.parseDependencies(line) + case "C:": + d := decodeChecksumLine(line) + if d != "" { + pkg.Digest = d + } } if pkg.Name != "" && pkg.Version != "" { @@ -206,3 +214,27 @@ func (a alpinePkgAnalyzer) Type() analyzer.Type { func (a alpinePkgAnalyzer) Version() int { return analyzerVersion } + +// decodeChecksumLine decodes checksum line +func decodeChecksumLine(line string) digest.Digest { + if len(line) < 2 { + log.Logger.Debugf("Unable to decode checksum line of apk package: %s", line) + return "" + } + // https://wiki.alpinelinux.org/wiki/Apk_spec#Package_Checksum_Field + // https://stackoverflow.com/a/71712569 + alg := digest.MD5 + d := line[2:] + if strings.HasPrefix(d, "Q1") { + alg = digest.SHA1 + d = d[2:] // remove `Q1` prefix + } + + decodedDigestString, err := base64.StdEncoding.DecodeString(d) + if err != nil { + log.Logger.Debugf("unable to decode digest: %s", err) + return "" + } + h := hex.EncodeToString(decodedDigestString) + return digest.NewDigestFromString(alg, h) +} diff --git a/pkg/fanal/analyzer/pkg/apk/apk_test.go b/pkg/fanal/analyzer/pkg/apk/apk_test.go index 7e9e97972e1..24d7624ae07 100644 --- a/pkg/fanal/analyzer/pkg/apk/apk_test.go +++ b/pkg/fanal/analyzer/pkg/apk/apk_test.go @@ -26,6 +26,7 @@ func TestParseApkInfo(t *testing.T) { SrcName: "musl", SrcVersion: "1.1.14-r10", Licenses: []string{"MIT"}, + Digest: "sha1:d68b402f35f57750f49156b0cb4e886a2ad35d2d", }, { ID: "busybox@1.24.2-r9", @@ -35,6 +36,7 @@ func TestParseApkInfo(t *testing.T) { SrcVersion: "1.24.2-r9", Licenses: []string{"GPL-2.0"}, DependsOn: []string{"musl@1.1.14-r10"}, + Digest: "sha1:ca124719267cd0bedc2f4cb850a286ac13f0ad44", }, { ID: "alpine-baselayout@3.0.3-r0", @@ -44,6 +46,7 @@ func TestParseApkInfo(t *testing.T) { SrcVersion: "3.0.3-r0", Licenses: []string{"GPL-2.0"}, DependsOn: []string{"busybox@1.24.2-r9", "musl@1.1.14-r10"}, + Digest: "sha1:a214896150411d72dd1fafdb32d1c6c4855cccfa", }, { ID: "alpine-keys@1.1-r0", @@ -52,6 +55,7 @@ func TestParseApkInfo(t *testing.T) { SrcName: "alpine-keys", SrcVersion: "1.1-r0", Licenses: []string{"GPL-3.0"}, + Digest: "sha1:4def7ffaee6aeba700c1d62570326f75cbb8fa25", }, { ID: "zlib@1.2.8-r2", @@ -61,6 +65,7 @@ func TestParseApkInfo(t *testing.T) { SrcVersion: "1.2.8-r2", Licenses: []string{"Zlib"}, DependsOn: []string{"musl@1.1.14-r10"}, + Digest: "sha1:efd04d34d40aa8eb331480127364c27a8ba760ef", }, { ID: "libcrypto1.0@1.0.2h-r1", @@ -70,6 +75,7 @@ func TestParseApkInfo(t *testing.T) { SrcVersion: "1.0.2h-r1", Licenses: []string{"openssl"}, DependsOn: []string{"musl@1.1.14-r10", "zlib@1.2.8-r2"}, + Digest: "sha1:65c860ff8f103b664f40ba849a3f5a51c69c8beb", }, { ID: "libssl1.0@1.0.2h-r1", @@ -78,6 +84,7 @@ func TestParseApkInfo(t *testing.T) { SrcName: "openssl", SrcVersion: "1.0.2h-r1", Licenses: []string{"openssl"}, + Digest: "sha1:7120f337e93b2b4c44e0f5f31a15b60dc678ca14", DependsOn: []string{ "libcrypto1.0@1.0.2h-r1", "musl@1.1.14-r10", @@ -90,6 +97,7 @@ func TestParseApkInfo(t *testing.T) { SrcName: "apk-tools", SrcVersion: "2.6.7-r0", Licenses: []string{"GPL-2.0"}, + Digest: "sha1:0990c0acd62b4175818c3a4cc60ed11f14e23bd8", DependsOn: []string{ "libcrypto1.0@1.0.2h-r1", "libssl1.0@1.0.2h-r1", @@ -104,6 +112,7 @@ func TestParseApkInfo(t *testing.T) { SrcName: "pax-utils", SrcVersion: "1.1.6-r0", Licenses: []string{"GPL-2.0"}, + Digest: "sha1:f9bab817c5ad93e92a6218bc0f7596b657c02d90", DependsOn: []string{"musl@1.1.14-r10"}, }, { @@ -113,6 +122,7 @@ func TestParseApkInfo(t *testing.T) { SrcName: "musl", SrcVersion: "1.1.14-r10", Licenses: []string{"MIT", "BSD-3-Clause", "GPL-2.0"}, + Digest: "sha1:608aa1dd39eff7bc6615d3e5e33383750f8f5ecc", DependsOn: []string{ "musl@1.1.14-r10", "scanelf@1.1.6-r0", @@ -125,6 +135,7 @@ func TestParseApkInfo(t *testing.T) { SrcName: "libc-dev", SrcVersion: "0.7-r0", Licenses: []string{"GPL-3.0"}, + Digest: "sha1:9055bc7afd76cf2672198042f72fc4a5ed4fa961", DependsOn: []string{"musl-utils@1.1.14-r10"}, }, { @@ -134,6 +145,7 @@ func TestParseApkInfo(t *testing.T) { SrcName: "pkgconf", SrcVersion: "1.6.0-r0", Licenses: []string{"ISC"}, + Digest: "sha1:e6242ac29589c8a84a4b179b491ea7c29fce66a9", DependsOn: []string{"musl@1.1.14-r10"}, }, @@ -144,6 +156,7 @@ func TestParseApkInfo(t *testing.T) { SrcName: "sqlite", SrcVersion: "3.26.0-r3", Licenses: []string{"Public-Domain"}, + Digest: "sha1:1464946c3a5f0dd5a67ca1af930fc17af7a74474", DependsOn: []string{"musl@1.1.14-r10"}, }, @@ -154,6 +167,7 @@ func TestParseApkInfo(t *testing.T) { SrcName: "test-parent", SrcVersion: "2.9.11_pre20061021-r2", Licenses: []string{"Public-Domain"}, + Digest: "sha1:f0bf315ec54828188910e4a665c00bc48bdbdd7d", DependsOn: []string{ "pkgconf@1.6.0-r0", "sqlite-libs@3.26.0-r3", diff --git a/pkg/fanal/artifact/image/image_test.go b/pkg/fanal/artifact/image/image_test.go index c180099e696..4416f869447 100644 --- a/pkg/fanal/artifact/image/image_test.go +++ b/pkg/fanal/artifact/image/image_test.go @@ -41,6 +41,7 @@ func TestArtifact_Inspect(t *testing.T) { SrcName: "alpine-baselayout", SrcVersion: "3.2.0-r3", Licenses: []string{"GPL-2.0"}, + Digest: "sha1:8f373f5b329c3aaf136eb30c63a387661ee0f3d0", DependsOn: []string{ "busybox@1.31.1-r9", "musl@1.1.24-r2", @@ -53,6 +54,7 @@ func TestArtifact_Inspect(t *testing.T) { SrcName: "alpine-keys", SrcVersion: "2.1-r2", Licenses: []string{"MIT"}, + Digest: "sha1:64929f85b7f8b4adbb664d905410312936b79d9b", }, { ID: "apk-tools@2.10.4-r3", @@ -61,6 +63,7 @@ func TestArtifact_Inspect(t *testing.T) { SrcName: "apk-tools", SrcVersion: "2.10.4-r3", Licenses: []string{"GPL-2.0"}, + Digest: "sha1:b15ad0c90e4493dfdc948d6b90a8e020da8936ef", DependsOn: []string{ "libcrypto1.1@1.1.1d-r3", "libssl1.1@1.1.1d-r3", @@ -75,6 +78,7 @@ func TestArtifact_Inspect(t *testing.T) { SrcName: "busybox", SrcVersion: "1.31.1-r9", Licenses: []string{"GPL-2.0"}, + Digest: "sha1:a457703d71654811ea28d8d27a5cfc49ece27b34", DependsOn: []string{ "musl@1.1.24-r2", }, @@ -89,6 +93,7 @@ func TestArtifact_Inspect(t *testing.T) { "MPL-2.0", "GPL-2.0", }, + Digest: "sha1:3aeb8a90d7179d2a187782e980a964494e08c5fb", }, { ID: "libc-utils@0.7.2-r0", @@ -97,6 +102,7 @@ func TestArtifact_Inspect(t *testing.T) { SrcName: "libc-dev", SrcVersion: "0.7.2-r0", Licenses: []string{"BSD-3-Clause"}, + Digest: "sha1:a7bf32bd32c6d3de2d1c4d7e753a0919b998cd01", DependsOn: []string{ "musl-utils@1.1.24-r2", }, @@ -108,6 +114,7 @@ func TestArtifact_Inspect(t *testing.T) { SrcName: "openssl", SrcVersion: "1.1.1d-r3", Licenses: []string{"OpenSSL"}, + Digest: "sha1:dd8fb9a3cce7b2bcf954271da62fb85dac2b106a", DependsOn: []string{ "musl@1.1.24-r2", }, @@ -119,6 +126,7 @@ func TestArtifact_Inspect(t *testing.T) { SrcName: "openssl", SrcVersion: "1.1.1d-r3", Licenses: []string{"OpenSSL"}, + Digest: "sha1:938d46e41b3e56b339a3aeb2d02fad3d75728f35", DependsOn: []string{ "libcrypto1.1@1.1.1d-r3", "musl@1.1.24-r2", @@ -131,6 +139,7 @@ func TestArtifact_Inspect(t *testing.T) { SrcName: "libtls-standalone", SrcVersion: "2.9.1-r0", Licenses: []string{"ISC"}, + Digest: "sha1:b2e5627a56378ea6eeb962a8f33722df9393c1c5", DependsOn: []string{ "ca-certificates-cacert@20191127-r1", "libcrypto1.1@1.1.1d-r3", @@ -145,6 +154,7 @@ func TestArtifact_Inspect(t *testing.T) { SrcName: "musl", SrcVersion: "1.1.24-r2", Licenses: []string{"MIT"}, + Digest: "sha1:cb2316a189ebee5282c4a9bd98794cc2477a74c6", }, { ID: "musl-utils@1.1.24-r2", @@ -157,6 +167,7 @@ func TestArtifact_Inspect(t *testing.T) { "BSD-3-Clause", "GPL-2.0", }, + Digest: "sha1:6d3b45e79dbab444ca7cbfa59e2833203be6fb6a", DependsOn: []string{ "musl@1.1.24-r2", "scanelf@1.2.4-r0", @@ -169,6 +180,7 @@ func TestArtifact_Inspect(t *testing.T) { SrcName: "pax-utils", SrcVersion: "1.2.4-r0", Licenses: []string{"GPL-2.0"}, + Digest: "sha1:d6147beb32bff803b5d9f83a3bec7ab319087185", DependsOn: []string{ "musl@1.1.24-r2", }, @@ -180,6 +192,7 @@ func TestArtifact_Inspect(t *testing.T) { SrcName: "busybox", SrcVersion: "1.31.1-r9", Licenses: []string{"GPL-2.0"}, + Digest: "sha1:3b685152af320120ae8941c740d3376b54e43c10", DependsOn: []string{ "libtls-standalone@2.9.1-r0", "musl@1.1.24-r2", @@ -192,6 +205,7 @@ func TestArtifact_Inspect(t *testing.T) { SrcName: "zlib", SrcVersion: "1.2.11-r3", Licenses: []string{"Zlib"}, + Digest: "sha1:acca078ee8baa93e005f57b2fae359c1efd443cd", DependsOn: []string{ "musl@1.1.24-r2", }, diff --git a/pkg/fanal/artifact/local/fs_test.go b/pkg/fanal/artifact/local/fs_test.go index af81b3353e6..673f7f337f4 100644 --- a/pkg/fanal/artifact/local/fs_test.go +++ b/pkg/fanal/artifact/local/fs_test.go @@ -47,7 +47,7 @@ func TestArtifact_Inspect(t *testing.T) { }, putBlobExpectation: cache.ArtifactCachePutBlobExpectation{ Args: cache.ArtifactCachePutBlobArgs{ - BlobID: "sha256:fc0c7d225197e1c103784139def1e34b642e8183cf54519cac79dd0cfdd19aba", + BlobID: "sha256:2846219523ad45fe4a17495304ed0a36163f1bd66e7fb0b4c19c5d1d4a966c82", BlobInfo: types.BlobInfo{ SchemaVersion: types.BlobJSONSchemaVersion, OS: types.OS{ @@ -65,6 +65,7 @@ func TestArtifact_Inspect(t *testing.T) { SrcName: "musl", SrcVersion: "1.1.24-r2", Licenses: []string{"MIT"}, + Digest: "sha1:cb2316a189ebee5282c4a9bd98794cc2477a74c6", }, }, }, @@ -76,9 +77,9 @@ func TestArtifact_Inspect(t *testing.T) { want: types.ArtifactReference{ Name: "host", Type: types.ArtifactFilesystem, - ID: "sha256:fc0c7d225197e1c103784139def1e34b642e8183cf54519cac79dd0cfdd19aba", + ID: "sha256:2846219523ad45fe4a17495304ed0a36163f1bd66e7fb0b4c19c5d1d4a966c82", BlobIDs: []string{ - "sha256:fc0c7d225197e1c103784139def1e34b642e8183cf54519cac79dd0cfdd19aba", + "sha256:2846219523ad45fe4a17495304ed0a36163f1bd66e7fb0b4c19c5d1d4a966c82", }, }, }, @@ -119,7 +120,7 @@ func TestArtifact_Inspect(t *testing.T) { }, putBlobExpectation: cache.ArtifactCachePutBlobExpectation{ Args: cache.ArtifactCachePutBlobArgs{ - BlobID: "sha256:fc0c7d225197e1c103784139def1e34b642e8183cf54519cac79dd0cfdd19aba", + BlobID: "sha256:2846219523ad45fe4a17495304ed0a36163f1bd66e7fb0b4c19c5d1d4a966c82", BlobInfo: types.BlobInfo{ SchemaVersion: types.BlobJSONSchemaVersion, OS: types.OS{ @@ -137,6 +138,7 @@ func TestArtifact_Inspect(t *testing.T) { SrcName: "musl", SrcVersion: "1.1.24-r2", Licenses: []string{"MIT"}, + Digest: "sha1:cb2316a189ebee5282c4a9bd98794cc2477a74c6", }, }, }, diff --git a/pkg/fanal/test/integration/testdata/goldens/packages/alpine-310.json.golden b/pkg/fanal/test/integration/testdata/goldens/packages/alpine-310.json.golden index cc208c7b87a..0efbf7bdebd 100644 --- a/pkg/fanal/test/integration/testdata/goldens/packages/alpine-310.json.golden +++ b/pkg/fanal/test/integration/testdata/goldens/packages/alpine-310.json.golden @@ -8,6 +8,7 @@ "Licenses": [ "GPL-2.0" ], + "Digest": "sha1:574d490311b68db01c0a3e44f5491be0cdc79250", "DependsOn": [ "busybox@1.30.1-r2", "musl@1.1.22-r3" @@ -26,6 +27,7 @@ "Licenses": [ "MIT" ], + "Digest": "sha1:6dd672e2dabc14aa324cf9cd4553e98b69a769c1", "Layer": { "Digest": "sha256:9d48c3bd43c520dc2784e868a780e976b207cbf493eaff8c6596eb871cbd9609", "DiffID": "sha256:03901b4a2ea88eeaad62dbe59b072b28b6efa00491962b8741081c5df50c65e0" @@ -40,6 +42,7 @@ "Licenses": [ "GPL-2.0" ], + "Digest": "sha1:e6393c9419776955346cddd70ad4ec66082a2705", "DependsOn": [ "libcrypto1.1@1.1.1c-r0", "libssl1.1@1.1.1c-r0", @@ -60,6 +63,7 @@ "Licenses": [ "GPL-2.0" ], + "Digest": "sha1:9c244d7f4909bffcef4c67380b6aed145c41a232", "DependsOn": [ "musl@1.1.22-r3" ], @@ -78,6 +82,7 @@ "MPL-2.0", "GPL-2.0" ], + "Digest": "sha1:0d69933c7cd071e82acb24c6e4268e4752f7a3f7", "Layer": { "Digest": "sha256:9d48c3bd43c520dc2784e868a780e976b207cbf493eaff8c6596eb871cbd9609", "DiffID": "sha256:03901b4a2ea88eeaad62dbe59b072b28b6efa00491962b8741081c5df50c65e0" @@ -92,6 +97,7 @@ "Licenses": [ "BSD-3-Clause" ], + "Digest": "sha1:1ff2cf7a0a53c1e83c8649f27b95aaa07bd4a83e", "DependsOn": [ "musl-utils@1.1.22-r3" ], @@ -109,6 +115,7 @@ "Licenses": [ "OpenSSL" ], + "Digest": "sha1:547053af84ac3667548b11b990d7b80ef23b9a3f", "DependsOn": [ "musl@1.1.22-r3" ], @@ -130,6 +137,7 @@ "libcrypto1.1@1.1.1c-r0", "musl@1.1.22-r3" ], + "Digest": "sha1:6f37a428d6f8de036a523d42e6b0c99288153c38", "Layer": { "Digest": "sha256:9d48c3bd43c520dc2784e868a780e976b207cbf493eaff8c6596eb871cbd9609", "DiffID": "sha256:03901b4a2ea88eeaad62dbe59b072b28b6efa00491962b8741081c5df50c65e0" @@ -144,6 +152,7 @@ "Licenses": [ "ISC" ], + "Digest": "sha1:f149b608e1e33cfad61fbcf9e3fdb6494f7d691a", "DependsOn": [ "ca-certificates-cacert@20190108-r0", "libcrypto1.1@1.1.1c-r0", @@ -164,6 +173,7 @@ "Licenses": [ "MIT" ], + "Digest": "sha1:d489e0f3fbb5548758f5ccd2c5a0cef70260ef62", "Layer": { "Digest": "sha256:9d48c3bd43c520dc2784e868a780e976b207cbf493eaff8c6596eb871cbd9609", "DiffID": "sha256:03901b4a2ea88eeaad62dbe59b072b28b6efa00491962b8741081c5df50c65e0" @@ -180,6 +190,7 @@ "BSD-3-Clause", "GPL-2.0" ], + "Digest": "sha1:8bb14c727be819d07a1e9d8b998dc94bde989205", "DependsOn": [ "musl@1.1.22-r3", "scanelf@1.2.3-r0" @@ -198,6 +209,7 @@ "Licenses": [ "GPL-2.0" ], + "Digest": "sha1:cb3059ce358cea0f5f78a0220a2980e6c4916a94", "DependsOn": [ "musl@1.1.22-r3" ], @@ -215,6 +227,7 @@ "Licenses": [ "GPL-2.0" ], + "Digest": "sha1:1f7afca8301f00cef8a9797124721d9f8c16f586", "DependsOn": [ "libtls-standalone@2.9.1-r0", "musl@1.1.22-r3" @@ -233,6 +246,7 @@ "Licenses": [ "Zlib" ], + "Digest": "sha1:bacb380dfa6f2f5e8dc366144f09b3181001cf76", "DependsOn": [ "musl@1.1.22-r3" ], diff --git a/pkg/fanal/test/integration/testdata/goldens/packages/vulnimage.json.golden b/pkg/fanal/test/integration/testdata/goldens/packages/vulnimage.json.golden index 7bbb3c3a2eb..3f69eb00ef1 100644 --- a/pkg/fanal/test/integration/testdata/goldens/packages/vulnimage.json.golden +++ b/pkg/fanal/test/integration/testdata/goldens/packages/vulnimage.json.golden @@ -3,6 +3,7 @@ "ID": ".composer-phpext-rundeps@0", "Name": ".composer-phpext-rundeps", "Version": "0", + "Digest": "sha1:6120632b2e7d0a3ceb27984e667f1601ef3f6f61", "DependsOn": [ "libsodium@1.0.15-r0", "musl@1.1.18-r3", @@ -17,6 +18,7 @@ "ID": ".persistent-deps@0", "Name": ".persistent-deps", "Version": "0", + "Digest": "sha1:fdb428017a69c58edbe2c141cf5277c76381d88a", "DependsOn": [ "ca-certificates@20171114-r0", "curl@7.61.0-r0", @@ -33,6 +35,7 @@ "ID": ".php-rundeps@0", "Name": ".php-rundeps", "Version": "0", + "Digest": "sha1:b55c2c60d52012cbfbd1b40d236e76490b1d2f46", "DependsOn": [ "libcurl@7.61.1-r0", "libedit@20170329.3.1-r3", @@ -57,6 +60,7 @@ "Licenses": [ "GPL-2.0" ], + "Digest": "sha1:6e1c83d84d2369825ec44b335e246cc812ee21e8", "DependsOn": [ "busybox@1.27.2-r11", "musl@1.1.18-r3" @@ -75,6 +79,7 @@ "Licenses": [ "MIT" ], + "Digest": "sha1:3458e5b2ab168697409f61d2afd35dea6287fbd2", "Layer": { "Digest": "sha256:c67f3896b22c1378881cbbb9c9d1edfe881fd07f713371835ef46d93c649684d", "DiffID": "sha256:ebf12965380b39889c99a9c02e82ba465f887b45975b6e389d42e9e6a3857888" @@ -89,6 +94,7 @@ "Licenses": [ "GPL-2.0" ], + "Digest": "sha1:599116788034fe9c0f9486edd4f4a5bf589f4806", "DependsOn": [ "libressl2.6-libcrypto@2.6.5-r0", "libressl2.6-libssl@2.6.5-r0", @@ -109,6 +115,7 @@ "Licenses": [ "ASL2.0" ], + "Digest": "sha1:ef13fd7436617f0d1664d824b0e89e516d57dbf6", "DependsOn": [ "libuuid@2.31-r0", "musl@1.1.18-r3" @@ -127,6 +134,7 @@ "Licenses": [ "ASL2.0" ], + "Digest": "sha1:bafbf610de141db01418fa88e91b05c69efeb608", "DependsOn": [ "apr@1.6.3-r0", "expat@2.2.5-r0", @@ -147,6 +155,7 @@ "Licenses": [ "GPL-3.0" ], + "Digest": "sha1:2a2bb204890224c98f6327d5c4da7ea291ad370f", "DependsOn": [ "busybox@1.27.2-r11", "musl@1.1.18-r3", @@ -167,6 +176,7 @@ "Licenses": [ "GPL-2.0" ], + "Digest": "sha1:7f9617f0e3abb6430216d33201e6d5b30d049fc5", "DependsOn": [ "musl@1.1.18-r3" ], @@ -185,6 +195,7 @@ "MPL-2.0", "GPL-2.0" ], + "Digest": "sha1:5aa669d28ef467b64451bd754af97b4f68cdd884", "DependsOn": [ "busybox@1.27.2-r11", "libressl2.6-libcrypto@2.6.5-r0", @@ -204,6 +215,7 @@ "Licenses": [ "MIT" ], + "Digest": "sha1:016d483d30cfea67c126965281160db475b6ca65", "DependsOn": [ "ca-certificates@20171114-r0", "libcurl@7.61.1-r0", @@ -224,6 +236,7 @@ "Licenses": [ "custom" ], + "Digest": "sha1:6a4d69ccb4da10b07ede9649b08aa323a8902790", "DependsOn": [ "musl@1.1.18-r3" ], @@ -241,6 +254,7 @@ "Licenses": [ "MIT" ], + "Digest": "sha1:5096efd90f782b0e54927539aa30f4134181d477", "DependsOn": [ "musl@1.1.18-r3" ], @@ -258,6 +272,7 @@ "Licenses": [ "GPL-3.0" ], + "Digest": "sha1:331bccf0688c10645a51523ef5590f3f2bebcbf9", "DependsOn": [ "musl@1.1.18-r3" ], @@ -275,6 +290,7 @@ "Licenses": [ "GPL-2.0" ], + "Digest": "sha1:acfbed348e588d90838c4a308428a16042ee9f30", "DependsOn": [ "expat@2.2.5-r0", "libcurl@7.61.1-r0", @@ -296,6 +312,7 @@ "Licenses": [ "BSD-3-Clause" ], + "Digest": "sha1:132242e396d99c2d06ee14c7ea4c3f3d02be102a", "DependsOn": [ "musl@1.1.18-r3" ], @@ -313,6 +330,7 @@ "Licenses": [ "BSD-3-Clause" ], + "Digest": "sha1:b149e07fcf3cd345e38023edca9b0c9ce7e821bc", "DependsOn": [ "musl-utils@1.1.18-r3" ], @@ -330,6 +348,7 @@ "Licenses": [ "MIT" ], + "Digest": "sha1:3dbd4ffbb43027efba686b75e4418d7e94ad8b46", "DependsOn": [ "ca-certificates@20171114-r0", "libressl2.6-libcrypto@2.6.5-r0", @@ -352,6 +371,7 @@ "Licenses": [ "BSD-3-Clause" ], + "Digest": "sha1:4d393236e43554c60c5aaaffbcca394f45adcfb8", "DependsOn": [ "musl@1.1.18-r3", "ncurses-libs@6.0_p20171125-r1" @@ -373,6 +393,7 @@ "DependsOn": [ "musl@1.1.18-r3" ], + "Digest": "sha1:9b28ec06ab670657cd47582bf4fe4b803cd93e28", "Layer": { "Digest": "sha256:c191915691a422a1b0230c9010165ff655204a9fd95e3b43151132bcb237826b", "DiffID": "sha256:2da3602d664dd3f71fae83cbc566d4e80b432c6ee8bb4efd94c8e85122f503d4" @@ -387,6 +408,7 @@ "Licenses": [ "custom" ], + "Digest": "sha1:684940a8557dc097623cdc6a551b2baad7a08b06", "DependsOn": [ "libressl2.6-libcrypto@2.6.5-r0", "libressl2.6-libssl@2.6.5-r0", @@ -407,6 +429,7 @@ "Licenses": [ "custom" ], + "Digest": "sha1:2718dc7d5a9a34ac650614600e16118e466317f7", "DependsOn": [ "musl@1.1.18-r3" ], @@ -424,6 +447,7 @@ "Licenses": [ "custom" ], + "Digest": "sha1:df902e38eab7ecbdf3d143a56c3caa511522f524", "DependsOn": [ "libressl2.6-libcrypto@2.6.5-r0", "musl@1.1.18-r3" @@ -442,6 +466,7 @@ "Licenses": [ "custom" ], + "Digest": "sha1:7740cbc6dee93683e6893edbe89715a2a99aa9b4", "DependsOn": [ "libressl2.6-libcrypto@2.6.5-r0", "libressl2.6-libssl@2.6.5-r0", @@ -461,6 +486,7 @@ "Licenses": [ "custom" ], + "Digest": "sha1:1f14d6b5e172b3b4643106f49a4dc85c9c517060", "DependsOn": [ "db@5.3.28-r0", "musl@1.1.18-r3" @@ -479,6 +505,7 @@ "Licenses": [ "ISC" ], + "Digest": "sha1:7fbed17399609f0613bede5c686d7a02169da7ee", "DependsOn": [ "musl@1.1.18-r3" ], @@ -496,6 +523,7 @@ "Licenses": [ "BSD-3-Clause" ], + "Digest": "sha1:953a992e9e05e10134651f8826403854240e739b", "DependsOn": [ "libressl2.6-libcrypto@2.6.5-r0", "musl@1.1.18-r3", @@ -520,6 +548,7 @@ "Public", "Domain" ], + "Digest": "sha1:d95c3db24000cb62331d3892fc1e44292799b4b2", "DependsOn": [ "musl@1.1.18-r3" ], @@ -537,6 +566,7 @@ "Licenses": [ "MIT" ], + "Digest": "sha1:990af059bbdb87a870c12f0959bb1b9b91bd57ba", "DependsOn": [ "musl@1.1.18-r3", "zlib@1.2.11-r1" @@ -555,6 +585,7 @@ "Licenses": [ "GPL-2.0" ], + "Digest": "sha1:42cc6d472044ac2936f00c412af0ae4e08fd599e", "DependsOn": [ "musl@1.1.18-r3", "python2@2.7.15-r2" @@ -573,6 +604,7 @@ "Licenses": [ "MIT" ], + "Digest": "sha1:5595b2575962e133096977497ef1582bcc76429e", "Layer": { "Digest": "sha256:c67f3896b22c1378881cbbb9c9d1edfe881fd07f713371835ef46d93c649684d", "DiffID": "sha256:ebf12965380b39889c99a9c02e82ba465f887b45975b6e389d42e9e6a3857888" @@ -589,6 +621,7 @@ "BSD-3-Clause", "GPL-2.0" ], + "Digest": "sha1:87d95e8fc8f4792b3e544a3576cb73f0a89bfa41", "DependsOn": [ "musl@1.1.18-r3", "scanelf@1.2.2-r1" @@ -607,6 +640,7 @@ "Licenses": [ "MIT" ], + "Digest": "sha1:f784fc9499dda6c6d13da34507efa7546368fff3", "DependsOn": [ "musl@1.1.18-r3", "ncurses-terminfo-base@6.0_p20171125-r1", @@ -626,6 +660,7 @@ "Licenses": [ "MIT" ], + "Digest": "sha1:113144a8d7eeb534dc692b66d45ec8ccdd4b972d", "DependsOn": [ "ncurses-terminfo-base@6.0_p20171125-r1" ], @@ -643,6 +678,7 @@ "Licenses": [ "MIT" ], + "Digest": "sha1:967549060a1cf0ef40e1f1d2fff56b8e45e999c2", "Layer": { "Digest": "sha256:3d6152f6ac208640f9fb494d1c379fe508db1fc5754cd08fefec200bddd13e0e", "DiffID": "sha256:6408527580eade39c2692dbb6b0f6a9321448d06ea1c2eef06bb7f37da9c5013" @@ -657,6 +693,7 @@ "Licenses": [ "as-is" ], + "Digest": "sha1:f1d37d2f20528e68bc78028934fa749abd56fcd9", "DependsOn": [ "libressl2.6-libcrypto@2.6.5-r0", "musl@1.1.18-r3", @@ -678,6 +715,7 @@ "Licenses": [ "as-is" ], + "Digest": "sha1:8cfbbee8796be1acaa03e8ee58f431dad21ef3c5", "DependsOn": [ "libressl2.6-libcrypto@2.6.5-r0", "musl@1.1.18-r3", @@ -698,6 +736,7 @@ "Licenses": [ "as-is" ], + "Digest": "sha1:c610fb52fb90da0e25eea69c1e55d02cf44ba05d", "DependsOn": [ "libressl2.6-libcrypto@2.6.5-r0", "musl@1.1.18-r3" @@ -716,6 +755,7 @@ "Licenses": [ "as-is" ], + "Digest": "sha1:326edd676b254aefe048536473c540b28fb335ce", "DependsOn": [ "libressl2.6-libcrypto@2.6.5-r0", "musl@1.1.18-r3", @@ -737,6 +777,7 @@ "Licenses": [ "as-is" ], + "Digest": "sha1:f055712504ebbe781cf4c6a6987a878067dd65fd", "Layer": { "Digest": "sha256:c191915691a422a1b0230c9010165ff655204a9fd95e3b43151132bcb237826b", "DiffID": "sha256:2da3602d664dd3f71fae83cbc566d4e80b432c6ee8bb4efd94c8e85122f503d4" @@ -751,6 +792,7 @@ "Licenses": [ "as-is" ], + "Digest": "sha1:6c1dcaaba744742843ca4766f21ca546e7813930", "DependsOn": [ "musl@1.1.18-r3" ], @@ -768,6 +810,7 @@ "Licenses": [ "GPL-3.0" ], + "Digest": "sha1:8ab18877f726014de8dff1368937414ae8929abd", "DependsOn": [ "musl@1.1.18-r3" ], @@ -785,6 +828,7 @@ "Licenses": [ "BSD-3-Clause" ], + "Digest": "sha1:5d9f8804b6343a6dd1df0d131b4f342294a423af", "DependsOn": [ "musl@1.1.18-r3" ], @@ -802,6 +846,7 @@ "Licenses": [ "ISC" ], + "Digest": "sha1:bcdf2647b07bae9fffd76433d0defcc6e8dbea21", "DependsOn": [ "musl@1.1.18-r3" ], @@ -819,6 +864,7 @@ "Licenses": [ "custom" ], + "Digest": "sha1:e535f131326fc346ffe23083b79fb688a220796a", "DependsOn": [ "expat@2.2.5-r0", "gdbm@1.13-r1", @@ -846,6 +892,7 @@ "Licenses": [ "GPL-3.0" ], + "Digest": "sha1:6796e379c3acec5edda98243e506a363d54c2854", "DependsOn": [ "musl@1.1.18-r3", "ncurses-libs@6.0_p20171125-r1" @@ -864,6 +911,7 @@ "Licenses": [ "GPL-2.0" ], + "Digest": "sha1:673d3ba729ab198f0120e3d1f37e993ee2f93c88", "DependsOn": [ "musl@1.1.18-r3" ], @@ -881,6 +929,7 @@ "Licenses": [ "ASL2.0" ], + "Digest": "sha1:7f3acf89cc921a20b621f297018caed2e939d873", "DependsOn": [ "apr-util@1.6.1-r1", "apr@1.6.3-r0", @@ -903,6 +952,7 @@ "Licenses": [ "custom" ], + "Digest": "sha1:963204681a8d8922da42739756caca5d0a4290f0", "DependsOn": [ "musl@1.1.18-r3" ], @@ -920,6 +970,7 @@ "Licenses": [ "GPL-2.0" ], + "Digest": "sha1:be991cfc32528659450b6dd21e855d638b5865a6", "DependsOn": [ "libressl2.6-libtls@2.6.5-r0", "musl@1.1.18-r3" @@ -939,6 +990,7 @@ "Apache-2.0", "BSD-3-Clause" ], + "Digest": "sha1:b3f0936eb24b3f61099cedfac29195dc04a08362", "DependsOn": [ "apr-util@1.6.1-r1", "apr@1.6.3-r0", @@ -962,6 +1014,7 @@ "Apache-2.0", "BSD-3-Clause" ], + "Digest": "sha1:159042d5715f6e501e73569ffd9b86530758b6d4", "DependsOn": [ "apr-util@1.6.1-r1", "apr@1.6.3-r0", @@ -987,6 +1040,7 @@ "Licenses": [ "GPL-3.0" ], + "Digest": "sha1:32ed0dea10cb4fc68f32e7466513230e09679d09", "DependsOn": [ "musl@1.1.18-r3" ], @@ -1004,6 +1058,7 @@ "Licenses": [ "MIT" ], + "Digest": "sha1:f88c6efbdbb698ba8a2db15ee88fa2b474002fb3", "DependsOn": [ "musl@1.1.18-r3" ], @@ -1021,6 +1076,7 @@ "Licenses": [ "custom" ], + "Digest": "sha1:fe745c838ec20816bc5c4d9e4fceb01dc866caac", "DependsOn": [ "musl@1.1.18-r3", "xz-libs@5.2.3-r1" @@ -1039,6 +1095,7 @@ "Licenses": [ "custom" ], + "Digest": "sha1:7aeb306958a1cb330a7bb8f7ce24ab6fe85c8b1f", "DependsOn": [ "musl@1.1.18-r3" ], @@ -1056,6 +1113,7 @@ "Licenses": [ "Zlib" ], + "Digest": "sha1:4869b83137ea8eab47c9f0b0e1085a5cc6ae2bb3", "DependsOn": [ "musl@1.1.18-r3" ], diff --git a/pkg/sbom/cyclonedx/marshal.go b/pkg/sbom/cyclonedx/marshal.go index 8cc7bfbe8a2..400b5e61e31 100644 --- a/pkg/sbom/cyclonedx/marshal.go +++ b/pkg/sbom/cyclonedx/marshal.go @@ -15,6 +15,7 @@ import ( dtypes "github.com/aquasecurity/trivy-db/pkg/types" "github.com/aquasecurity/trivy-db/pkg/vulnsrc/vulnerability" + "github.com/aquasecurity/trivy/pkg/digest" ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" "github.com/aquasecurity/trivy/pkg/log" "github.com/aquasecurity/trivy/pkg/purl" @@ -206,7 +207,7 @@ func (e *Marshaler) marshalComponents(r types.Report, bomRef string) (*[]cdx.Com parents := ftypes.Packages(result.Packages).ParentDeps() for _, pkg := range result.Packages { - pkgComponent, err := pkgToCdxComponent(result.Type, r.Metadata, pkg) + pkgComponent, err := pkgToCdxComponent(result.Type, r.Metadata, result.Class, pkg) if err != nil { return nil, nil, nil, xerrors.Errorf("failed to parse pkg: %w", err) } @@ -448,12 +449,24 @@ func (e *Marshaler) resultToCdxComponent(r types.Result, osFound *ftypes.OS) cdx return component } -func pkgToCdxComponent(pkgType string, meta types.Metadata, pkg ftypes.Package) (cdx.Component, error) { +func pkgToCdxComponent(pkgType string, meta types.Metadata, class types.ResultClass, pkg ftypes.Package) (cdx.Component, error) { pu, err := purl.NewPackageURL(pkgType, meta, pkg) if err != nil { return cdx.Component{}, xerrors.Errorf("failed to new package purl: %w", err) } properties := cdxProperties(pkgType, pkg) + var hashes *[]cdx.Hash + if pkg.Digest != "" && class == types.ClassOSPkg { + if alg := cdxHashAlgorithm(pkg.Digest.Algorithm()); alg != "" { + hashes = &[]cdx.Hash{ + { + Algorithm: alg, + Value: pkg.Digest.Encoded(), + }, + } + } + + } component := cdx.Component{ Type: cdx.ComponentTypeLibrary, Name: pkg.Name, @@ -461,6 +474,7 @@ func pkgToCdxComponent(pkgType string, meta types.Metadata, pkg ftypes.Package) BOMRef: pu.BOMRef(), PackageURL: pu.ToString(), Properties: properties, + Hashes: hashes, } if len(pkg.Licenses) != 0 { @@ -703,3 +717,17 @@ func cdxAffects(ref, version string) cdx.Affects { }, } } + +func cdxHashAlgorithm(algorithm digest.Algorithm) cdx.HashAlgorithm { + switch algorithm { + case digest.SHA1: + return cdx.HashAlgoSHA1 + case digest.SHA256: + return cdx.HashAlgoSHA256 + case digest.MD5: + return cdx.HashAlgoMD5 + default: + log.Logger.Debugf("Unable to convert %q algorithm to CycloneDX format", algorithm) + return "" + } +} diff --git a/pkg/sbom/spdx/marshal.go b/pkg/sbom/spdx/marshal.go index 21480269285..4e6524c0c13 100644 --- a/pkg/sbom/spdx/marshal.go +++ b/pkg/sbom/spdx/marshal.go @@ -346,6 +346,17 @@ func (m *Marshaler) pkgToSpdxPackage(t, pkgDownloadLocation string, class types. Supplier: pkg.Maintainer, } } + + var checksum []spdx.Checksum + if pkg.Digest != "" && class == types.ClassOSPkg { + checksum = []spdx.Checksum{ + { + Algorithm: common.ChecksumAlgorithm(pkg.Digest.Algorithm()), + Value: pkg.Digest.Encoded(), + }, + } + } + return spdx.Package{ PackageName: pkg.Name, PackageVersion: utils.FormatVersion(pkg), @@ -363,6 +374,7 @@ func (m *Marshaler) pkgToSpdxPackage(t, pkgDownloadLocation string, class types. PackageAttributionTexts: attrTexts, PrimaryPackagePurpose: PackagePurposeLibrary, PackageSupplier: supplier, + PackageChecksums: checksum, Files: files, }, nil }