Skip to content

Commit

Permalink
Add x509 svid verify options (#176)
Browse files Browse the repository at this point in the history
Signed-off-by: Andrew Harding <[email protected]>
  • Loading branch information
azdagron authored Feb 28, 2022
1 parent 40dfa55 commit 23abb23
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 5 deletions.
36 changes: 33 additions & 3 deletions v2/svid/x509svid/verify.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package x509svid

import (
"crypto/x509"
"time"

"github.com/spiffe/go-spiffe/v2/bundle/x509bundle"
"github.com/spiffe/go-spiffe/v2/internal/x509util"
Expand All @@ -11,10 +12,28 @@ import (

var x509svidErr = errs.Class("x509svid")

// VerifyOption is an option used when verifying X509-SVIDs.
type VerifyOption interface {
apply(config *verifyConfig)
}

// WithTime sets the time used when verifying validity periods on the X509-SVID.
// If not used, the current time will be used.
func WithTime(now time.Time) VerifyOption {
return verifyOption(func(config *verifyConfig) {
config.now = now
})
}

// Verify verifies an X509-SVID chain using the X.509 bundle source. It
// returns the SPIFFE ID of the X509-SVID and one or more chains back to a root
// in the bundle.
func Verify(certs []*x509.Certificate, bundleSource x509bundle.Source) (spiffeid.ID, [][]*x509.Certificate, error) {
func Verify(certs []*x509.Certificate, bundleSource x509bundle.Source, opts ...VerifyOption) (spiffeid.ID, [][]*x509.Certificate, error) {
config := &verifyConfig{}
for _, opt := range opts {
opt.apply(config)
}

switch {
case len(certs) == 0:
return spiffeid.ID{}, nil, x509svidErr.New("empty certificates chain")
Expand Down Expand Up @@ -46,6 +65,7 @@ func Verify(certs []*x509.Certificate, bundleSource x509bundle.Source) (spiffeid
Roots: x509util.NewCertPool(bundle.X509Authorities()),
Intermediates: x509util.NewCertPool(certs[1:]),
KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageAny},
CurrentTime: config.now,
})
if err != nil {
return id, nil, x509svidErr.New("could not verify leaf certificate: %w", err)
Expand All @@ -57,7 +77,7 @@ func Verify(certs []*x509.Certificate, bundleSource x509bundle.Source) (spiffeid
// ParseAndVerify parses and verifies an X509-SVID chain using the X.509
// bundle source. It returns the SPIFFE ID of the X509-SVID and one or more
// chains back to a root in the bundle.
func ParseAndVerify(rawCerts [][]byte, bundleSource x509bundle.Source) (spiffeid.ID, [][]*x509.Certificate, error) {
func ParseAndVerify(rawCerts [][]byte, bundleSource x509bundle.Source, opts ...VerifyOption) (spiffeid.ID, [][]*x509.Certificate, error) {
var certs []*x509.Certificate
for _, rawCert := range rawCerts {
cert, err := x509.ParseCertificate(rawCert)
Expand All @@ -66,7 +86,7 @@ func ParseAndVerify(rawCerts [][]byte, bundleSource x509bundle.Source) (spiffeid
}
certs = append(certs, cert)
}
return Verify(certs, bundleSource)
return Verify(certs, bundleSource, opts...)
}

// IDFromCert extracts the SPIFFE ID from the URI SAN of the provided
Expand All @@ -81,3 +101,13 @@ func IDFromCert(cert *x509.Certificate) (spiffeid.ID, error) {
}
return spiffeid.FromURI(cert.URIs[0])
}

type verifyConfig struct {
now time.Time
}

type verifyOption func(config *verifyConfig)

func (fn verifyOption) apply(config *verifyConfig) {
fn(config)
}
14 changes: 12 additions & 2 deletions v2/svid/x509svid/verify_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"crypto/x509"
"net/url"
"testing"
"time"

"github.com/spiffe/go-spiffe/v2/bundle/spiffebundle"
"github.com/spiffe/go-spiffe/v2/bundle/x509bundle"
Expand Down Expand Up @@ -37,6 +38,7 @@ func TestVerify(t *testing.T) {
name string
chain []*x509.Certificate
bundle x509bundle.Source
opts []x509svid.VerifyOption
expectedID spiffeid.ID
err string
}{
Expand Down Expand Up @@ -110,6 +112,13 @@ func TestVerify(t *testing.T) {
bundle: bundle1,
err: "x509svid: leaf certificate with KeyCrlSign key usage",
},
{
name: "with time",
chain: leaf1,
bundle: bundle1,
opts: []x509svid.VerifyOption{x509svid.WithTime(leaf1[0].NotAfter.Add(time.Second))},
err: "x509svid: could not verify leaf certificate: x509: certificate has expired",
},
{
name: "success",
chain: leaf1,
Expand All @@ -120,9 +129,10 @@ func TestVerify(t *testing.T) {
for _, testCase := range testCases {
testCase := testCase // alias loop var as it is used in the closure
t.Run(testCase.name, func(t *testing.T) {
_, verifiedChains, err := x509svid.Verify(testCase.chain, testCase.bundle)
_, verifiedChains, err := x509svid.Verify(testCase.chain, testCase.bundle, testCase.opts...)
if testCase.err != "" {
require.EqualError(t, err, testCase.err)
require.Error(t, err)
require.Contains(t, err.Error(), testCase.err)
return
}
require.NoError(t, err)
Expand Down

0 comments on commit 23abb23

Please sign in to comment.