Skip to content

Commit

Permalink
Address review
Browse files Browse the repository at this point in the history
Signed-off-by: Slavek Kabrda <[email protected]>
  • Loading branch information
bkabrda committed Aug 26, 2024
1 parent 46179d8 commit f609695
Show file tree
Hide file tree
Showing 4 changed files with 169 additions and 3 deletions.
6 changes: 5 additions & 1 deletion cmd/tuf/server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ var (
// Name of the "secret" where we create one entry per key JSON definition as generated by TUF, e.g. "root.json", "timestamp.json", ...
keysSecretName = flag.String("keyssecret", "", "Name of the secret to create for generated keys (keys won't be stored unless this is provided)")
noK8s = flag.Bool("no-k8s", false, "Run in a non-k8s environment")
metadataTargets = flag.Bool("metadata-targets", true, "Serve individual targets with custom Sigstore metadata")
metadataTargets = flag.Bool("metadata-targets", true, "Serve individual targets with custom Sigstore metadata. This will be deprecated and removed in the future.")
trustedRoot = flag.Bool("trusted-root", true, "Generate and serve trusted_root.json")
)

Expand Down Expand Up @@ -198,6 +198,10 @@ func main() {

ctx := signals.NewContext()

if *metadataTargets {
logging.FromContext(ctx).Warnf("Serving individual TUF targets with custom Sigstore metadata will be deprecated and removed in the future.")
}

serve := false
init := false
overwrite := true
Expand Down
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ require (
github.com/sigstore/sigstore v1.8.8
github.com/sigstore/sigstore-go v0.6.1-0.20240821212051-2198ac32dd94
github.com/sigstore/timestamp-authority v1.2.2
github.com/stretchr/testify v1.9.0
github.com/theupdateframework/go-tuf v0.7.0
github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399
go.uber.org/zap v1.27.0
Expand Down Expand Up @@ -224,6 +225,7 @@ require (
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.55.0 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
Expand Down
7 changes: 5 additions & 2 deletions pkg/repo/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"context"
"crypto"
"crypto/ecdsa"
"crypto/ed25519"
"crypto/elliptic"
"crypto/rsa"
"crypto/sha256"
Expand Down Expand Up @@ -191,7 +192,7 @@ func CreateRepoWithOptions(ctx context.Context, files map[string][]byte, options
// * CreateRepoOptions.AddMetadataTargets: true
// * CreateRepoOptions.AddTrustedRoot: false
func CreateRepo(ctx context.Context, files map[string][]byte) (tuf.LocalStore, string, error) {
return CreateRepoWithOptions(ctx, files, CreateRepoOptions{AddMetadataTargets: true, AddTrustedRoot: false})
return CreateRepoWithOptions(ctx, files, CreateRepoOptions{AddMetadataTargets: true, AddTrustedRoot: true})
}

func constructTrustedRoot(targets []TargetWithMetadata) (*TargetWithMetadata, error) {
Expand Down Expand Up @@ -334,6 +335,8 @@ func getKeyWithDetails(key []byte) (crypto.PublicKey, crypto.Hash, error) {
default:
return 0, 0, fmt.Errorf("unsupported public modulus %d", v.Size())
}
case *ed25519.PublicKey:
hashFunc = crypto.SHA512
default:
return 0, 0, errors.New("unknown public key type")
}
Expand Down Expand Up @@ -400,7 +403,7 @@ func concatCertChain(leaf []byte, intermediate [][]byte, root []byte) []byte {

func getTargetUsage(name string) string {
for _, knownTargetType := range []string{FulcioTarget, RekorTarget, CTFETarget, TSATarget} {
if strings.Contains(name, strings.ToLower(knownTargetType)) {
if strings.Contains(strings.ToLower(name), strings.ToLower(knownTargetType)) {
return knownTargetType
}
}
Expand Down
157 changes: 157 additions & 0 deletions pkg/repo/repo_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,14 @@ package repo
import (
"bytes"
"context"
"fmt"
"os"
"path/filepath"
"regexp"
"testing"

"github.com/sigstore/scaffolding/pkg/certs"
"github.com/stretchr/testify/require"
)

const (
Expand Down Expand Up @@ -56,6 +61,125 @@ c70LfiFo//8/QsvyjLIUtEWHTkGeuf4PpbYXr5qpJ6tWhG2MARxdeg8CAwEAAQ==
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEF6j2sTItLcs0wKoOpMzI+9lJmCzf
N6mY2prOeaBRV2dnsJzC94hOxkM5pSp9nbAK1TBOI45fOOPsH2rSR++HrA==
-----END PUBLIC KEY-----`

tsaCertChain = `-----BEGIN CERTIFICATE-----
MIIB3DCCAWKgAwIBAgIUchkNsH36Xa04b1LqIc+qr9DVecMwCgYIKoZIzj0EAwMw
MjEVMBMGA1UEChMMR2l0SHViLCBJbmMuMRkwFwYDVQQDExBUU0EgaW50ZXJtZWRp
YXRlMB4XDTIzMDQxNDAwMDAwMFoXDTI0MDQxMzAwMDAwMFowMjEVMBMGA1UEChMM
R2l0SHViLCBJbmMuMRkwFwYDVQQDExBUU0EgVGltZXN0YW1waW5nMFkwEwYHKoZI
zj0CAQYIKoZIzj0DAQcDQgAEUD5ZNbSqYMd6r8qpOOEX9ibGnZT9GsuXOhr/f8U9
FJugBGExKYp40OULS0erjZW7xV9xV52NnJf5OeDq4e5ZKqNWMFQwDgYDVR0PAQH/
BAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMIMAwGA1UdEwEB/wQCMAAwHwYDVR0j
BBgwFoAUaW1RudOgVt0leqY0WKYbuPr47wAwCgYIKoZIzj0EAwMDaAAwZQIwbUH9
HvD4ejCZJOWQnqAlkqURllvu9M8+VqLbiRK+zSfZCZwsiljRn8MQQRSkXEE5AjEA
g+VxqtojfVfu8DhzzhCx9GKETbJHb19iV72mMKUbDAFmzZ6bQ8b54Zb8tidy5aWe
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIICEDCCAZWgAwIBAgIUX8ZO5QXP7vN4dMQ5e9sU3nub8OgwCgYIKoZIzj0EAwMw
ODEVMBMGA1UEChMMR2l0SHViLCBJbmMuMR8wHQYDVQQDExZJbnRlcm5hbCBTZXJ2
aWNlcyBSb290MB4XDTIzMDQxNDAwMDAwMFoXDTI4MDQxMjAwMDAwMFowMjEVMBMG
A1UEChMMR2l0SHViLCBJbmMuMRkwFwYDVQQDExBUU0EgaW50ZXJtZWRpYXRlMHYw
EAYHKoZIzj0CAQYFK4EEACIDYgAEvMLY/dTVbvIJYANAuszEwJnQE1llftynyMKI
Mhh48HmqbVr5ygybzsLRLVKbBWOdZ21aeJz+gZiytZetqcyF9WlER5NEMf6JV7ZN
ojQpxHq4RHGoGSceQv/qvTiZxEDKo2YwZDAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0T
AQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUaW1RudOgVt0leqY0WKYbuPr47wAwHwYD
VR0jBBgwFoAU9NYYlobnAG4c0/qjxyH/lq/wz+QwCgYIKoZIzj0EAwMDaQAwZgIx
AK1B185ygCrIYFlIs3GjswjnwSMG6LY8woLVdakKDZxVa8f8cqMs1DhcxJ0+09w9
5QIxAO+tBzZk7vjUJ9iJgD4R6ZWTxQWKqNm74jO99o+o9sv4FI/SZTZTFyMn0IJE
HdNmyA==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIB9DCCAXqgAwIBAgIUa/JAkdUjK4JUwsqtaiRJGWhqLSowCgYIKoZIzj0EAwMw
ODEVMBMGA1UEChMMR2l0SHViLCBJbmMuMR8wHQYDVQQDExZJbnRlcm5hbCBTZXJ2
aWNlcyBSb290MB4XDTIzMDQxNDAwMDAwMFoXDTMzMDQxMTAwMDAwMFowODEVMBMG
A1UEChMMR2l0SHViLCBJbmMuMR8wHQYDVQQDExZJbnRlcm5hbCBTZXJ2aWNlcyBS
b290MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEf9jFAXxz4kx68AHRMOkFBhflDcMT
vzaXz4x/FCcXjJ/1qEKon/qPIGnaURskDtyNbNDOpeJTDDFqt48iMPrnzpx6IZwq
emfUJN4xBEZfza+pYt/iyod+9tZr20RRWSv/o0UwQzAOBgNVHQ8BAf8EBAMCAQYw
EgYDVR0TAQH/BAgwBgEB/wIBAjAdBgNVHQ4EFgQU9NYYlobnAG4c0/qjxyH/lq/w
z+QwCgYIKoZIzj0EAwMDaAAwZQIxALZLZ8BgRXzKxLMMN9VIlO+e4hrBnNBgF7tz
7Hnrowv2NetZErIACKFymBlvWDvtMAIwZO+ki6ssQ1bsZo98O8mEAf2NZ7iiCgDD
U0Vwjeco6zyeh0zBTs9/7gV6AHNQ53xD
-----END CERTIFICATE-----`

trJSONValidForStart = "2024-08-26T12:03:30.241272895Z"
trJSON = `{
"mediaType": "application/vnd.dev.sigstore.trustedroot+json;version=0.1",
"tlogs": [
{
"hashAlgorithm": "SHA2_256",
"publicKey": {
"rawBytes": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEF6j2sTItLcs0wKoOpMzI+9lJmCzfN6mY2prOeaBRV2dnsJzC94hOxkM5pSp9nbAK1TBOI45fOOPsH2rSR++HrA==",
"keyDetails": "PKIX_ECDSA_P256_SHA_256",
"validFor": {
"start": "2024-08-26T12:03:30.241272895Z"
}
},
"logId": {
"keyId": "xBzny6gmou42sCYrHOzNuGqi1s2cMxcCEq1wrKF9XDs="
}
}
],
"certificateAuthorities": [
{
"subject": {
"organization": "RedHat",
"commonName": "testcert"
},
"certChain": {
"certificates": [
{
"rawBytes": "MIICNzCCAd2gAwIBAgITPLBoBQhl1hqFND9S+SGWbfzaRTAKBggqhkjOPQQDAjBoMQswCQYDVQQGEwJVSzESMBAGA1UECBMJV2lsdHNoaXJlMRMwEQYDVQQHEwpDaGlwcGVuaGFtMQ8wDQYDVQQKEwZSZWRIYXQxDDAKBgNVBAsTA0NUTzERMA8GA1UEAxMIdGVzdGNlcnQwHhcNMjEwMzEyMjMyNDQ5WhcNMzEwMjI4MjMyNDQ5WjBoMQswCQYDVQQGEwJVSzESMBAGA1UECBMJV2lsdHNoaXJlMRMwEQYDVQQHEwpDaGlwcGVuaGFtMQ8wDQYDVQQKEwZSZWRIYXQxDDAKBgNVBAsTA0NUTzERMA8GA1UEAxMIdGVzdGNlcnQwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQRn+Alyof6xP3GQClSwgV0NFuYYEwmKP/WLWr/LwB6LUYzt5v49RlqG83KuaJSpeOj7G7MVABdpIZYWwqAiZV3o2YwZDAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBATAdBgNVHQ4EFgQUT8Jwm6JuVb0dsiuHUROiHOOVHVkwHwYDVR0jBBgwFoAUT8Jwm6JuVb0dsiuHUROiHOOVHVkwCgYIKoZIzj0EAwIDSAAwRQIhAJkNZmP6sKA+8EebRXFkBa9DPjacBpTcOljJotvKidRhAiAuNrIazKEw2G4dw8x1z6EYk9G+7fJP5m93bjm/JfMBtA=="
}
]
},
"validFor": {
"start": "2021-03-12T23:24:49Z",
"end": "2031-02-28T23:24:49Z"
}
}
],
"ctlogs": [
{
"hashAlgorithm": "SHA2_256",
"publicKey": {
"rawBytes": "MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAu1Ah4n2P8JGt92Qg86FdR8f1pou43yndggMuRCX0JB+bLn1rUFRAKQVd+xnnd4PXJLLdml8ZohCr0lhBuMxZ7zBzt0T98kblUCxBgABPNpWIkTgacyC8MlIYY/yBSuDWAJOA5IKi4Hh9nI+Mmb/FXgbOz5a5mZx8w7pMiTMu0+Rd9cPzRkUZDQfZsLONr6PwmyCAIL1oK80fevxKZPME0UV8bFPWnRxeVaFr5ddd/DOenV8H6SPyr4ODbSOItpl53y6Az0m3FTIUf8cSsyR7dfE4zpA3M4djjtoKDNFRsTjU2RWVQW9XMaxzznGVGhLEwkC+sYjR5NQvH5iiRvV18q+CGQqNX2+WWM3SPuty3nc86RBNR0FOgSQA0TL2OAs6bJNmfzcwZxAKYbj7/88tj6qrjLaQtFTbBm2a7+TAQfs3UTiQi00zEDYqeSj2WQvacNm1dWEAyx0QNLHiKGTn4TShGj8LUoGyjJ26Y6VPsotvCoj8jM0eaN8Pc9/AYywVI+QktjaPZa7KGH3XJHJkTIQQRcUxOtDstKpcriAefDs8jjL5ju9t5J3qEvgzmclNJKRnla4p3maM0vk+8cC7EXMV4P1zuCwr3akaHFJo5Y0aFhKsnHqTc70LfiFo//8/QsvyjLIUtEWHTkGeuf4PpbYXr5qpJ6tWhG2MARxdeg8CAwEAAQ==",
"keyDetails": "PKIX_RSA_PKCS1V15_4096_SHA256",
"validFor": {
"start": "2024-08-26T12:03:30.241272895Z"
}
},
"logId": {
"keyId": "G3CTL21UG8/5ygV+/WVy/pvB8nUiZGOEnMVKIEDzPxY="
}
}
],
"timestampAuthorities": [
{
"subject": {
"organization": "GitHub, Inc.",
"commonName": "Internal Services Root"
},
"certChain": {
"certificates": [
{
"rawBytes": "MIIB3DCCAWKgAwIBAgIUchkNsH36Xa04b1LqIc+qr9DVecMwCgYIKoZIzj0EAwMwMjEVMBMGA1UEChMMR2l0SHViLCBJbmMuMRkwFwYDVQQDExBUU0EgaW50ZXJtZWRpYXRlMB4XDTIzMDQxNDAwMDAwMFoXDTI0MDQxMzAwMDAwMFowMjEVMBMGA1UEChMMR2l0SHViLCBJbmMuMRkwFwYDVQQDExBUU0EgVGltZXN0YW1waW5nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEUD5ZNbSqYMd6r8qpOOEX9ibGnZT9GsuXOhr/f8U9FJugBGExKYp40OULS0erjZW7xV9xV52NnJf5OeDq4e5ZKqNWMFQwDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMIMAwGA1UdEwEB/wQCMAAwHwYDVR0jBBgwFoAUaW1RudOgVt0leqY0WKYbuPr47wAwCgYIKoZIzj0EAwMDaAAwZQIwbUH9HvD4ejCZJOWQnqAlkqURllvu9M8+VqLbiRK+zSfZCZwsiljRn8MQQRSkXEE5AjEAg+VxqtojfVfu8DhzzhCx9GKETbJHb19iV72mMKUbDAFmzZ6bQ8b54Zb8tidy5aWe"
},
{
"rawBytes": "MIICEDCCAZWgAwIBAgIUX8ZO5QXP7vN4dMQ5e9sU3nub8OgwCgYIKoZIzj0EAwMwODEVMBMGA1UEChMMR2l0SHViLCBJbmMuMR8wHQYDVQQDExZJbnRlcm5hbCBTZXJ2aWNlcyBSb290MB4XDTIzMDQxNDAwMDAwMFoXDTI4MDQxMjAwMDAwMFowMjEVMBMGA1UEChMMR2l0SHViLCBJbmMuMRkwFwYDVQQDExBUU0EgaW50ZXJtZWRpYXRlMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEvMLY/dTVbvIJYANAuszEwJnQE1llftynyMKIMhh48HmqbVr5ygybzsLRLVKbBWOdZ21aeJz+gZiytZetqcyF9WlER5NEMf6JV7ZNojQpxHq4RHGoGSceQv/qvTiZxEDKo2YwZDAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUaW1RudOgVt0leqY0WKYbuPr47wAwHwYDVR0jBBgwFoAU9NYYlobnAG4c0/qjxyH/lq/wz+QwCgYIKoZIzj0EAwMDaQAwZgIxAK1B185ygCrIYFlIs3GjswjnwSMG6LY8woLVdakKDZxVa8f8cqMs1DhcxJ0+09w95QIxAO+tBzZk7vjUJ9iJgD4R6ZWTxQWKqNm74jO99o+o9sv4FI/SZTZTFyMn0IJEHdNmyA=="
},
{
"rawBytes": "MIIB9DCCAXqgAwIBAgIUa/JAkdUjK4JUwsqtaiRJGWhqLSowCgYIKoZIzj0EAwMwODEVMBMGA1UEChMMR2l0SHViLCBJbmMuMR8wHQYDVQQDExZJbnRlcm5hbCBTZXJ2aWNlcyBSb290MB4XDTIzMDQxNDAwMDAwMFoXDTMzMDQxMTAwMDAwMFowODEVMBMGA1UEChMMR2l0SHViLCBJbmMuMR8wHQYDVQQDExZJbnRlcm5hbCBTZXJ2aWNlcyBSb290MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEf9jFAXxz4kx68AHRMOkFBhflDcMTvzaXz4x/FCcXjJ/1qEKon/qPIGnaURskDtyNbNDOpeJTDDFqt48iMPrnzpx6IZwqemfUJN4xBEZfza+pYt/iyod+9tZr20RRWSv/o0UwQzAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBAjAdBgNVHQ4EFgQU9NYYlobnAG4c0/qjxyH/lq/wz+QwCgYIKoZIzj0EAwMDaAAwZQIxALZLZ8BgRXzKxLMMN9VIlO+e4hrBnNBgF7tz7Hnrowv2NetZErIACKFymBlvWDvtMAIwZO+ki6ssQ1bsZo98O8mEAf2NZ7iiCgDDU0Vwjeco6zyeh0zBTs9/7gV6AHNQ53xD"
}
]
},
"validFor": {
"start": "2023-04-14T00:00:00Z",
"end": "2024-04-13T00:00:00Z"
}
}
]
}`
)

func TestCreateRepo(t *testing.T) {
Expand Down Expand Up @@ -125,3 +249,36 @@ func TestCompressUncompressFS(t *testing.T) {
t.Errorf("Roundtripped rekor differs:\n%s\n%s", rekorPublicKey, string(rtRekor))
}
}

func TestConstructTrustedRoot(t *testing.T) {
tsaCerts, err := certs.SplitCertChain([]byte(tsaCertChain), "tsa")
if err != nil {
t.Fatalf("Failed to split TSA cert chain: %v", err)
}

targets := []TargetWithMetadata{
{Name: "fulcio.crt.pem", Bytes: []byte(fulcioRootCert)},
{Name: "ctfe.pub", Bytes: []byte(ctlogPublicKey)},
{Name: "rekor.pub", Bytes: []byte(rekorPublicKey)},
}

for k, v := range tsaCerts {
targets = append(targets, TargetWithMetadata{Name: k, Bytes: v})
}

tr, err := constructTrustedRoot(targets)
if err != nil {
t.Fatalf("Failed to construct trusted root: %v", err)
}
if tr.Name != "trusted_root.json" {
t.Fatalf("Wrong name for trusted root target. Expected 'trusted_root.json', got '%s'", tr.Name)
}
actualTr := string(tr.Bytes)

// the "validFor" for tlog/ctlog keys will be current time; let's replace them
// to be the time from the expected sample
re := regexp.MustCompile(`"validFor"\s*:\s*\{\s*"start"\s*:\s*"[^"]+"\s*\}`)
actualTr = re.ReplaceAllString(actualTr, fmt.Sprintf(`"validFor": {"start": "%s"}`, trJSONValidForStart))

require.JSONEq(t, trJSON, actualTr)
}

0 comments on commit f609695

Please sign in to comment.