Skip to content

Commit

Permalink
Add additional validation for nil elements in Bundles (#285)
Browse files Browse the repository at this point in the history
Signed-off-by: Cody Soyland <codysoyland@github.com>
  • Loading branch information
codysoyland committed Sep 4, 2024
1 parent 725e508 commit e50c2d7
Show file tree
Hide file tree
Showing 2 changed files with 162 additions and 6 deletions.
30 changes: 26 additions & 4 deletions pkg/bundle/bundle.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ var ErrUnsupportedMediaType = fmt.Errorf("%w: unsupported media type", ErrValida
var ErrMissingVerificationMaterial = fmt.Errorf("%w: missing verification material", ErrValidation)
var ErrUnimplemented = errors.New("unimplemented")
var ErrInvalidAttestation = fmt.Errorf("%w: invalid attestation", ErrValidation)
var ErrMissingEnvelope = fmt.Errorf("%w: missing envelope", ErrInvalidAttestation)
var ErrMissingEnvelope = fmt.Errorf("%w: missing valid envelope", ErrInvalidAttestation)
var ErrDecodingJSON = fmt.Errorf("%w: decoding json", ErrInvalidAttestation)
var ErrDecodingB64 = fmt.Errorf("%w: decoding base64", ErrInvalidAttestation)

Expand Down Expand Up @@ -196,7 +196,7 @@ func validateBundle(b *protobundle.Bundle) error {
switch b.VerificationMaterial.Content.(type) {
case *protobundle.VerificationMaterial_PublicKey, *protobundle.VerificationMaterial_Certificate, *protobundle.VerificationMaterial_X509CertificateChain:
default:
return fmt.Errorf("invalid verififcation material content: verification material must be one of public key, x509 certificate and x509 certificate chain")
return fmt.Errorf("invalid verification material content: verification material must be one of public key, x509 certificate and x509 certificate chain")
}

return nil
Expand Down Expand Up @@ -245,8 +245,11 @@ func (b *Bundle) VerificationContent() (verify.VerificationContent, error) {

switch content := b.VerificationMaterial.GetContent().(type) {
case *protobundle.VerificationMaterial_X509CertificateChain:
if content.X509CertificateChain == nil {
return nil, ErrMissingVerificationMaterial
}
certs := content.X509CertificateChain.GetCertificates()
if len(certs) == 0 {
if len(certs) == 0 || certs[0].RawBytes == nil {
return nil, ErrMissingVerificationMaterial
}
parsedCert, err := x509.ParseCertificate(certs[0].RawBytes)
Expand All @@ -258,6 +261,9 @@ func (b *Bundle) VerificationContent() (verify.VerificationContent, error) {
}
return cert, nil
case *protobundle.VerificationMaterial_Certificate:
if content.Certificate == nil || content.Certificate.RawBytes == nil {
return nil, ErrMissingVerificationMaterial
}
parsedCert, err := x509.ParseCertificate(content.Certificate.RawBytes)
if err != nil {
return nil, ErrValidationError(err)
Expand All @@ -267,6 +273,9 @@ func (b *Bundle) VerificationContent() (verify.VerificationContent, error) {
}
return cert, nil
case *protobundle.VerificationMaterial_PublicKey:
if content.PublicKey == nil {
return nil, ErrMissingVerificationMaterial
}
pk := &PublicKey{
hint: content.PublicKey.Hint,
}
Expand Down Expand Up @@ -318,6 +327,9 @@ func (b *Bundle) SignatureContent() (verify.SignatureContent, error) {
}
return envelope, nil
case *protobundle.Bundle_MessageSignature:
if content.MessageSignature == nil || content.MessageSignature.MessageDigest == nil {
return nil, ErrMissingVerificationMaterial
}
return NewMessageSignature(
content.MessageSignature.MessageDigest.Digest,
protocommon.HashAlgorithm_name[int32(content.MessageSignature.MessageDigest.Algorithm)],
Expand Down Expand Up @@ -372,11 +384,21 @@ func (b *Bundle) MinVersion(expectVersion string) bool {
}

func parseEnvelope(input *protodsse.Envelope) (*Envelope, error) {
if input == nil {
return nil, ErrMissingEnvelope
}
output := &dsse.Envelope{}
output.Payload = base64.StdEncoding.EncodeToString([]byte(input.GetPayload()))
payload := input.GetPayload()
if payload == nil {
return nil, ErrMissingEnvelope
}
output.Payload = base64.StdEncoding.EncodeToString([]byte(payload))
output.PayloadType = string(input.GetPayloadType())
output.Signatures = make([]dsse.Signature, len(input.GetSignatures()))
for i, sig := range input.GetSignatures() {
if sig == nil {
return nil, ErrMissingEnvelope
}
output.Signatures[i].KeyID = sig.GetKeyid()
output.Signatures[i].Sig = base64.StdEncoding.EncodeToString(sig.GetSig())
}
Expand Down
138 changes: 136 additions & 2 deletions pkg/bundle/bundle_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (

protobundle "github.com/sigstore/protobuf-specs/gen/pb-go/bundle/v1"
protocommon "github.com/sigstore/protobuf-specs/gen/pb-go/common/v1"
protodsse "github.com/sigstore/protobuf-specs/gen/pb-go/dsse"
rekorv1 "github.com/sigstore/protobuf-specs/gen/pb-go/rekor/v1"
_ "github.com/sigstore/rekor/pkg/types/hashedrekord"
"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -669,6 +670,53 @@ func TestVerificationContent(t *testing.T) {
},
wantErr: true,
},
{
name: "certificate chain with nil bytes",
pb: Bundle{
Bundle: &protobundle.Bundle{
VerificationMaterial: &protobundle.VerificationMaterial{
Content: &protobundle.VerificationMaterial_X509CertificateChain{
X509CertificateChain: &protocommon.X509CertificateChain{
Certificates: []*protocommon.X509Certificate{
{
RawBytes: nil,
},
},
},
},
},
},
},
wantErr: true,
},
{
name: "certificate chain with nil cert",
pb: Bundle{
Bundle: &protobundle.Bundle{
VerificationMaterial: &protobundle.VerificationMaterial{
Content: &protobundle.VerificationMaterial_X509CertificateChain{
X509CertificateChain: &protocommon.X509CertificateChain{
Certificates: nil,
},
},
},
},
},
wantErr: true,
},
{
name: "certificate chain with nil chain",
pb: Bundle{
Bundle: &protobundle.Bundle{
VerificationMaterial: &protobundle.VerificationMaterial{
Content: &protobundle.VerificationMaterial_X509CertificateChain{
X509CertificateChain: nil,
},
},
},
},
wantErr: true,
},
{
name: "certificate",
pb: Bundle{
Expand Down Expand Up @@ -699,6 +747,36 @@ func TestVerificationContent(t *testing.T) {
},
wantErr: true,
},
{
name: "certificate with nil bytes",
pb: Bundle{
Bundle: &protobundle.Bundle{
VerificationMaterial: &protobundle.VerificationMaterial{
Content: &protobundle.VerificationMaterial_Certificate{
Certificate: &protocommon.X509Certificate{
RawBytes: nil,
},
},
},
},
},
wantErr: true,
},
{
name: "empty certificate",
pb: Bundle{
Bundle: &protobundle.Bundle{
VerificationMaterial: &protobundle.VerificationMaterial{
Content: &protobundle.VerificationMaterial_Certificate{
Certificate: &protocommon.X509Certificate{
RawBytes: nil,
},
},
},
},
},
wantErr: true,
},
{
name: "public key",
pb: Bundle{
Expand All @@ -712,6 +790,19 @@ func TestVerificationContent(t *testing.T) {
},
wantPublicKey: true,
},
{
name: "nil public key",
pb: Bundle{
Bundle: &protobundle.Bundle{
VerificationMaterial: &protobundle.VerificationMaterial{
Content: &protobundle.VerificationMaterial_PublicKey{
PublicKey: nil,
},
},
},
},
wantErr: true,
},
}
for _, tt := range tests {
tt := tt
Expand Down Expand Up @@ -742,16 +833,50 @@ func TestSignatureContent(t *testing.T) {
pb Bundle
wantEnvelope bool
wantSignature bool
wantErr bool
}{
{
name: "dsse envelope",
pb: Bundle{
Bundle: &protobundle.Bundle{
Content: &protobundle.Bundle_DsseEnvelope{},
Content: &protobundle.Bundle_DsseEnvelope{
DsseEnvelope: &protodsse.Envelope{
Payload: []byte{},
Signatures: []*protodsse.Signature{{Sig: []byte{}, Keyid: ""}},
},
},
},
},
wantEnvelope: true,
},
{
name: "dsse envelope with nil signature",
pb: Bundle{
Bundle: &protobundle.Bundle{
Content: &protobundle.Bundle_DsseEnvelope{
DsseEnvelope: &protodsse.Envelope{
Payload: []byte{},
Signatures: []*protodsse.Signature{nil},
},
},
},
},
wantErr: true,
},
{
name: "dsse envelope with nil payload",
pb: Bundle{
Bundle: &protobundle.Bundle{
Content: &protobundle.Bundle_DsseEnvelope{
DsseEnvelope: &protodsse.Envelope{
Payload: nil,
Signatures: []*protodsse.Signature{{Sig: []byte{}, Keyid: ""}},
},
},
},
},
wantErr: true,
},
{
name: "message signature",
pb: Bundle{
Expand All @@ -770,6 +895,10 @@ func TestSignatureContent(t *testing.T) {
tt := tt
t.Run(tt.name, func(t *testing.T) {
got, gotErr := tt.pb.SignatureContent()
if tt.wantErr {
require.Error(t, gotErr)
return
}
require.NoError(t, gotErr)
if tt.wantEnvelope {
require.NotNil(t, got.EnvelopeContent())
Expand All @@ -794,7 +923,12 @@ func TestEnvelope(t *testing.T) {
name: "dsse envelope",
pb: Bundle{
Bundle: &protobundle.Bundle{
Content: &protobundle.Bundle_DsseEnvelope{},
Content: &protobundle.Bundle_DsseEnvelope{
DsseEnvelope: &protodsse.Envelope{
Payload: []byte{},
Signatures: []*protodsse.Signature{{Sig: []byte{}, Keyid: ""}},
},
},
},
},
},
Expand Down

0 comments on commit e50c2d7

Please sign in to comment.