diff --git a/dsse/dsse_test.go b/dsse/dsse_test.go index a23b01f2..3cd88772 100644 --- a/dsse/dsse_test.go +++ b/dsse/dsse_test.go @@ -16,19 +16,17 @@ package dsse import ( "bytes" - "context" "crypto" "crypto/rand" "crypto/rsa" "crypto/x509" "crypto/x509/pkix" - "fmt" - "io" "math/big" "testing" "time" "github.com/in-toto/go-witness/cryptoutil" + "github.com/in-toto/go-witness/timestamp" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -235,17 +233,17 @@ func TestTimestamp(t *testing.T) { require.NoError(t, err) v, err := s.Verifier() require.NoError(t, err) - expectedTimestampers := []dummyTimestamper{ - {t: time.Now()}, - {t: time.Now().Add(12 * time.Hour)}, + expectedTimestampers := []timestamp.FakeTimestamper{ + {T: time.Now()}, + {T: time.Now().Add(12 * time.Hour)}, } - unexpectedTimestampers := []dummyTimestamper{ - {t: time.Now().Add(36 * time.Hour)}, - {t: time.Now().Add(128 * time.Hour)}, + unexpectedTimestampers := []timestamp.FakeTimestamper{ + {T: time.Now().Add(36 * time.Hour)}, + {T: time.Now().Add(128 * time.Hour)}, } - allTimestampers := make([]Timestamper, 0) - allTimestampVerifiers := make([]TimestampVerifier, 0) + allTimestampers := make([]timestamp.Timestamper, 0) + allTimestampVerifiers := make([]timestamp.TimestampVerifier, 0) for _, expected := range expectedTimestampers { allTimestampers = append(allTimestampers, expected) allTimestampVerifiers = append(allTimestampVerifiers, expected) @@ -265,24 +263,3 @@ func TestTimestamp(t *testing.T) { assert.Len(t, approvedVerifiers[0].PassedTimestampVerifiers, len(expectedTimestampers)) assert.ElementsMatch(t, approvedVerifiers[0].PassedTimestampVerifiers, expectedTimestampers) } - -type dummyTimestamper struct { - t time.Time -} - -func (dt dummyTimestamper) Timestamp(context.Context, io.Reader) ([]byte, error) { - return []byte(dt.t.Format(time.RFC3339)), nil -} - -func (dt dummyTimestamper) Verify(ctx context.Context, ts io.Reader, sig io.Reader) (time.Time, error) { - b, err := io.ReadAll(ts) - if err != nil { - return time.Time{}, err - } - - if string(b) != dt.t.Format(time.RFC3339) { - return time.Time{}, fmt.Errorf("mismatched time") - } - - return dt.t, nil -} diff --git a/dsse/sign.go b/dsse/sign.go index 25b958ec..7092203c 100644 --- a/dsse/sign.go +++ b/dsse/sign.go @@ -22,15 +22,12 @@ import ( "io" "github.com/in-toto/go-witness/cryptoutil" + "github.com/in-toto/go-witness/timestamp" ) -type Timestamper interface { - Timestamp(context.Context, io.Reader) ([]byte, error) -} - type signOptions struct { signers []cryptoutil.Signer - timestampers []Timestamper + timestampers []timestamp.Timestamper } type SignOption func(*signOptions) @@ -41,7 +38,7 @@ func SignWithSigners(signers ...cryptoutil.Signer) SignOption { } } -func SignWithTimestampers(timestampers ...Timestamper) SignOption { +func SignWithTimestampers(timestampers ...timestamp.Timestamper) SignOption { return func(so *signOptions) { so.timestampers = timestampers } diff --git a/dsse/verify.go b/dsse/verify.go index 328a23fd..b028b8a6 100644 --- a/dsse/verify.go +++ b/dsse/verify.go @@ -18,23 +18,19 @@ import ( "bytes" "context" "crypto/x509" - "io" "time" "github.com/in-toto/go-witness/cryptoutil" "github.com/in-toto/go-witness/log" + "github.com/in-toto/go-witness/timestamp" ) -type TimestampVerifier interface { - Verify(context.Context, io.Reader, io.Reader) (time.Time, error) -} - type verificationOptions struct { roots []*x509.Certificate intermediates []*x509.Certificate verifiers []cryptoutil.Verifier threshold int - timestampVerifiers []TimestampVerifier + timestampVerifiers []timestamp.TimestampVerifier } type VerificationOption func(*verificationOptions) @@ -63,7 +59,7 @@ func VerifyWithThreshold(threshold int) VerificationOption { } } -func VerifyWithTimestampVerifiers(verifiers ...TimestampVerifier) VerificationOption { +func VerifyWithTimestampVerifiers(verifiers ...timestamp.TimestampVerifier) VerificationOption { return func(vo *verificationOptions) { vo.timestampVerifiers = verifiers } @@ -71,7 +67,7 @@ func VerifyWithTimestampVerifiers(verifiers ...TimestampVerifier) VerificationOp type PassedVerifier struct { Verifier cryptoutil.Verifier - PassedTimestampVerifiers []TimestampVerifier + PassedTimestampVerifiers []timestamp.TimestampVerifier } func (e Envelope) Verify(opts ...VerificationOption) ([]PassedVerifier, error) { @@ -121,7 +117,7 @@ func (e Envelope) Verify(opts ...VerificationOption) ([]PassedVerifier, error) { } } else { var passedVerifier cryptoutil.Verifier - passedTimestampVerifiers := []TimestampVerifier{} + passedTimestampVerifiers := []timestamp.TimestampVerifier{} for _, timestampVerifier := range options.timestampVerifiers { for _, sigTimestamp := range sig.Timestamps { diff --git a/run.go b/run.go index b6ccd2ca..dcd52c82 100644 --- a/run.go +++ b/run.go @@ -25,6 +25,7 @@ import ( "github.com/in-toto/go-witness/cryptoutil" "github.com/in-toto/go-witness/dsse" "github.com/in-toto/go-witness/intoto" + "github.com/in-toto/go-witness/timestamp" ) type runOptions struct { @@ -32,7 +33,7 @@ type runOptions struct { signer cryptoutil.Signer attestors []attestation.Attestor attestationOpts []attestation.AttestationContextOption - timestampers []dsse.Timestamper + timestampers []timestamp.Timestamper } type RunOption func(ro *runOptions) @@ -49,7 +50,7 @@ func RunWithAttestationOpts(opts ...attestation.AttestationContextOption) RunOpt } } -func RunWithTimestampers(ts ...dsse.Timestamper) RunOption { +func RunWithTimestampers(ts ...timestamp.Timestamper) RunOption { return func(ro *runOptions) { ro.timestampers = ts } diff --git a/timestamp/fake.go b/timestamp/fake.go new file mode 100644 index 00000000..1d509546 --- /dev/null +++ b/timestamp/fake.go @@ -0,0 +1,43 @@ +// Copyright 2022 The Witness Contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package timestamp + +import ( + "context" + "fmt" + "io" + "time" +) + +type FakeTimestamper struct { + T time.Time +} + +func (ft FakeTimestamper) Timestamp(context.Context, io.Reader) ([]byte, error) { + return []byte(ft.T.Format(time.RFC3339)), nil +} + +func (ft FakeTimestamper) Verify(ctx context.Context, ts io.Reader, sig io.Reader) (time.Time, error) { + b, err := io.ReadAll(ts) + if err != nil { + return time.Time{}, err + } + + if string(b) != ft.T.Format(time.RFC3339) { + return time.Time{}, fmt.Errorf("mismatched time") + } + + return ft.T, nil +} diff --git a/timestamp/timestamp.go b/timestamp/timestamp.go new file mode 100644 index 00000000..64081900 --- /dev/null +++ b/timestamp/timestamp.go @@ -0,0 +1,29 @@ +// Copyright 2022 The Witness Contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package timestamp + +import ( + "context" + "io" + "time" +) + +type TimestampVerifier interface { + Verify(context.Context, io.Reader, io.Reader) (time.Time, error) +} + +type Timestamper interface { + Timestamp(context.Context, io.Reader) ([]byte, error) +} diff --git a/verify.go b/verify.go index 68cd5c76..d31159eb 100644 --- a/verify.go +++ b/verify.go @@ -40,7 +40,7 @@ func VerifySignature(r io.Reader, verifiers ...cryptoutil.Verifier) (dsse.Envelo } type verifyOptions struct { - policyTimestampAuthorities []dsse.TimestampVerifier + policyTimestampAuthorities []timestamp.TimestampVerifier policyCARoots []*x509.Certificate policyCAIntermediates []*x509.Certificate policyEnvelope dsse.Envelope @@ -67,7 +67,7 @@ func VerifyWithCollectionSource(source source.Sourcer) VerifyOption { } } -func VerifyWithPolicyTimestampAuthorities(authorities []dsse.TimestampVerifier) VerifyOption { +func VerifyWithPolicyTimestampAuthorities(authorities []timestamp.TimestampVerifier) VerifyOption { return func(vo *verifyOptions) { vo.policyTimestampAuthorities = authorities } @@ -127,7 +127,7 @@ func Verify(ctx context.Context, policyEnvelope dsse.Envelope, policyVerifiers [ return nil, fmt.Errorf("failed to load policy timestamp authorities: %w", err) } - timestampVerifiers := make([]dsse.TimestampVerifier, 0) + timestampVerifiers := make([]timestamp.TimestampVerifier, 0) for _, timestampAuthority := range timestampAuthoritiesById { certs := []*x509.Certificate{timestampAuthority.Root} certs = append(certs, timestampAuthority.Intermediates...)