Skip to content

Commit

Permalink
feat: use rekor integrated time as a trusted time stamp
Browse files Browse the repository at this point in the history
Uses the rekor entry's trusted timestamp as a trusted time when
evaluating signatures with a valid x509 certificate attached.

Signed-off-by: Mikhail Swift <[email protected]>
  • Loading branch information
mikhailswift authored and colek42 committed Feb 4, 2022
1 parent 800abd4 commit 8524008
Show file tree
Hide file tree
Showing 5 changed files with 34 additions and 6 deletions.
10 changes: 9 additions & 1 deletion pkg/cryptoutil/verifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"crypto/x509"
"fmt"
"io"
"time"
)

type Verifier interface {
Expand All @@ -36,6 +37,7 @@ type verifierOptions struct {
roots []*x509.Certificate
intermediates []*x509.Certificate
hash crypto.Hash
trustedTime time.Time
}

func VerifyWithRoots(roots []*x509.Certificate) VerifierOption {
Expand All @@ -56,6 +58,12 @@ func VerifyWithHash(h crypto.Hash) VerifierOption {
}
}

func VerifyWithTrustedTime(t time.Time) VerifierOption {
return func(vo *verifierOptions) {
vo.trustedTime = t
}
}

func NewVerifier(pub interface{}, opts ...VerifierOption) (Verifier, error) {
options := &verifierOptions{
hash: crypto.SHA256,
Expand All @@ -73,7 +81,7 @@ func NewVerifier(pub interface{}, opts ...VerifierOption) (Verifier, error) {
case ed25519.PublicKey:
return NewED25519Verifier(key), nil
case *x509.Certificate:
return NewX509Verifier(key, options.intermediates, options.roots)
return NewX509Verifier(key, options.intermediates, options.roots, options.trustedTime)
default:
return nil, ErrUnsupportedKeyType{
t: fmt.Sprintf("%T", pub),
Expand Down
6 changes: 5 additions & 1 deletion pkg/cryptoutil/x509.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,18 @@ import (
"crypto/x509"
"encoding/pem"
"io"
"time"
)

type X509Verifier struct {
cert *x509.Certificate
roots []*x509.Certificate
intermediates []*x509.Certificate
verifier Verifier
trustedTime time.Time
}

func NewX509Verifier(cert *x509.Certificate, intermediates, roots []*x509.Certificate) (*X509Verifier, error) {
func NewX509Verifier(cert *x509.Certificate, intermediates, roots []*x509.Certificate, trustedTime time.Time) (*X509Verifier, error) {
verifier, err := NewVerifier(cert.PublicKey)
if err != nil {
return nil, err
Expand All @@ -38,6 +40,7 @@ func NewX509Verifier(cert *x509.Certificate, intermediates, roots []*x509.Certif
roots: roots,
intermediates: intermediates,
verifier: verifier,
trustedTime: trustedTime,
}, nil
}

Expand All @@ -49,6 +52,7 @@ func (v *X509Verifier) Verify(body io.Reader, sig []byte) error {
rootPool := certificatesToPool(v.roots)
intermediatePool := certificatesToPool(v.intermediates)
if _, err := v.cert.Verify(x509.VerifyOptions{
CurrentTime: v.trustedTime,
Roots: rootPool,
Intermediates: intermediatePool,
}); err != nil {
Expand Down
11 changes: 9 additions & 2 deletions pkg/cryptoutil/x509_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,16 +143,23 @@ func TestX509(t *testing.T) {
sig, err := signer.Sign(bytes.NewReader(data))
require.NoError(t, err)

verifier, err := NewX509Verifier(leaf, []*x509.Certificate{intermediate}, []*x509.Certificate{root})
// test success and failure with expected and unexpected data
verifier, err := NewX509Verifier(leaf, []*x509.Certificate{intermediate}, []*x509.Certificate{root}, time.Time{})
require.NoError(t, err)
err = verifier.Verify(bytes.NewReader(data), sig)
assert.NoError(t, err)
err = verifier.Verify(bytes.NewReader([]byte("this is not the signed data")), sig)
assert.Error(t, err)

verifier, err = NewX509Verifier(leaf, []*x509.Certificate{intermediate}, nil)
// test without roots
verifier, err = NewX509Verifier(leaf, []*x509.Certificate{intermediate}, nil, time.Time{})
require.NoError(t, err)
err = verifier.Verify(bytes.NewReader(data), sig)
assert.Error(t, err)

// test invalid time, certificate didn't exist at the "trusted time"
verifier, err = NewX509Verifier(leaf, []*x509.Certificate{intermediate}, []*x509.Certificate{root}, time.Now().Add(-1*time.Hour))
require.NoError(t, err)
err = verifier.Verify(bytes.NewReader(data), sig)
assert.Error(t, err)
}
10 changes: 9 additions & 1 deletion pkg/dsse/dsse.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"encoding/pem"
"fmt"
"io"
"time"

"github.com/testifysec/witness/pkg/cryptoutil"
)
Expand Down Expand Up @@ -111,6 +112,7 @@ type verificationOptions struct {
roots []*x509.Certificate
intermediates []*x509.Certificate
verifiers []cryptoutil.Verifier
trustedTime time.Time
}

func WithRoots(roots []*x509.Certificate) VerificationOption {
Expand All @@ -131,6 +133,12 @@ func WithVerifiers(verifiers []cryptoutil.Verifier) VerificationOption {
}
}

func WithTrustedTime(time time.Time) VerificationOption {
return func(vo *verificationOptions) {
vo.trustedTime = time
}
}

func (e Envelope) Verify(opts ...VerificationOption) ([]cryptoutil.Verifier, error) {
options := &verificationOptions{}
for _, opt := range opts {
Expand All @@ -156,7 +164,7 @@ func (e Envelope) Verify(opts ...VerificationOption) ([]cryptoutil.Verifier, err
continue
}

verifier, err := cryptoutil.NewX509Verifier(cert, options.intermediates, options.roots)
verifier, err := cryptoutil.NewX509Verifier(cert, options.intermediates, options.roots, options.trustedTime)
if err != nil {
return nil, err
}
Expand Down
3 changes: 2 additions & 1 deletion pkg/rekor/rekor.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"encoding/base64"
"errors"
"fmt"
"time"

"github.com/go-openapi/runtime"
"github.com/sigstore/rekor/pkg/client"
Expand Down Expand Up @@ -160,7 +161,7 @@ func ParseEnvelopeFromEntry(entry *models.LogEntryAnon) (dsse.Envelope, error) {
return env, fmt.Errorf("failed to decode signature: %w", err)
}

verifier, err := cryptoutil.NewVerifierFromReader(bytes.NewReader(sig.PublicKey))
verifier, err := cryptoutil.NewVerifierFromReader(bytes.NewReader(sig.PublicKey), cryptoutil.VerifyWithTrustedTime(time.Unix(*entry.IntegratedTime, 0)))
if err != nil {
return env, fmt.Errorf("failed to create verifier from public key on rekor entry: %w", err)
}
Expand Down

0 comments on commit 8524008

Please sign in to comment.