Skip to content

Commit

Permalink
Add specific suffixes mediaTypes to sboms (#1663)
Browse files Browse the repository at this point in the history
Signed-off-by: hectorj2f <[email protected]>
  • Loading branch information
Hector Fernandez authored Mar 26, 2022
1 parent db90d13 commit 34d0838
Show file tree
Hide file tree
Showing 5 changed files with 432 additions and 5 deletions.
28 changes: 24 additions & 4 deletions cmd/cosign/cli/options/attach.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,10 @@ func (o *AttachSignatureOptions) AddFlags(cmd *cobra.Command) {

// AttachSBOMOptions is the top level wrapper for the attach sbom command.
type AttachSBOMOptions struct {
SBOM string
SBOMType string
Registry RegistryOptions
SBOM string
SBOMType string
SBOMInputFormat string
Registry RegistryOptions
}

var _ Interface = (*AttachSBOMOptions)(nil)
Expand All @@ -62,15 +63,34 @@ func (o *AttachSBOMOptions) AddFlags(cmd *cobra.Command) {

cmd.Flags().StringVar(&o.SBOMType, "type", "spdx",
"type of sbom (spdx|cyclonedx|syft)")

cmd.Flags().StringVar(&o.SBOMInputFormat, "input-format", "",
"type of sbom input format (json|xml|text)")
}

func (o *AttachSBOMOptions) MediaType() (types.MediaType, error) {
switch o.SBOMType {
case "cyclonedx":
return ctypes.CycloneDXMediaType, nil
if o.SBOMInputFormat != "" && o.SBOMInputFormat != ctypes.XMLInputFormat && o.SBOMInputFormat != ctypes.JSONInputFormat {
return "invalid", fmt.Errorf("invalid SBOM input format: %q, expected (json|xml)", o.SBOMInputFormat)
}
if o.SBOMInputFormat == ctypes.JSONInputFormat {
return ctypes.CycloneDXJSONMediaType, nil
}
return ctypes.CycloneDXXMLMediaType, nil

case "spdx":
if o.SBOMInputFormat != "" && o.SBOMInputFormat != ctypes.TextInputFormat && o.SBOMInputFormat != ctypes.JSONInputFormat {
return "invalid", fmt.Errorf("invalid SBOM input format: %q, expected (json|text)", o.SBOMInputFormat)
}
if o.SBOMInputFormat == ctypes.JSONInputFormat {
return ctypes.SPDXJSONMediaType, nil
}
return ctypes.SPDXMediaType, nil
case "syft":
if o.SBOMInputFormat != "" && o.SBOMInputFormat != ctypes.JSONInputFormat {
return "invalid", fmt.Errorf("invalid SBOM input format: %q, expected (json)", o.SBOMInputFormat)
}
return ctypes.SyftMediaType, nil
default:
return "unknown", fmt.Errorf("unknown SBOM type: %q, expected (spdx|cyclonedx|syft)", o.SBOMType)
Expand Down
1 change: 1 addition & 0 deletions doc/cosign_attach_sbom.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

118 changes: 118 additions & 0 deletions pkg/oci/signature/layer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
//
// Copyright 2021 The Sigstore Authors.
//
// 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 signature

import (
"crypto/x509"
"encoding/json"
"fmt"
"io"
"strings"

v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/pkg/errors"
"github.com/sigstore/cosign/pkg/cosign/bundle"
"github.com/sigstore/cosign/pkg/oci"
"github.com/sigstore/sigstore/pkg/cryptoutils"
)

const (
sigkey = "dev.cosignproject.cosign/signature"
certkey = "dev.sigstore.cosign/certificate"
chainkey = "dev.sigstore.cosign/chain"
BundleKey = "dev.sigstore.cosign/bundle"
)

type sigLayer struct {
v1.Layer
desc v1.Descriptor
}

func New(l v1.Layer, desc v1.Descriptor) oci.Signature {
return &sigLayer{
Layer: l,
desc: desc,
}
}

var _ oci.Signature = (*sigLayer)(nil)

// Annotations implements oci.Signature
func (s *sigLayer) Annotations() (map[string]string, error) {
return s.desc.Annotations, nil
}

// Payload implements oci.Signature
func (s *sigLayer) Payload() ([]byte, error) {
// Compressed is a misnomer here, we just want the raw bytes from the registry.
r, err := s.Layer.Compressed()
if err != nil {
return nil, err
}
payload, err := io.ReadAll(r)
if err != nil {
return nil, err
}
return payload, nil
}

// Base64Signature implements oci.Signature
func (s *sigLayer) Base64Signature() (string, error) {
b64sig, ok := s.desc.Annotations[sigkey]
if !ok {
return "", fmt.Errorf("signature layer %s is missing %q annotation", s.desc.Digest, sigkey)
}
return b64sig, nil
}

// Cert implements oci.Signature
func (s *sigLayer) Cert() (*x509.Certificate, error) {
certPEM := s.desc.Annotations[certkey]
if certPEM == "" {
return nil, nil
}
certs, err := cryptoutils.LoadCertificatesFromPEM(strings.NewReader(certPEM))
if err != nil {
return nil, err
}
return certs[0], nil
}

// Chain implements oci.Signature
func (s *sigLayer) Chain() ([]*x509.Certificate, error) {
chainPEM := s.desc.Annotations[chainkey]
if chainPEM == "" {
return nil, nil
}
certs, err := cryptoutils.LoadCertificatesFromPEM(strings.NewReader(chainPEM))
if err != nil {
return nil, err
}
return certs, nil
}

// Bundle implements oci.Signature
func (s *sigLayer) Bundle() (*bundle.RekorBundle, error) {
val := s.desc.Annotations[BundleKey]
if val == "" {
return nil, nil
}
var b bundle.RekorBundle
if err := json.Unmarshal([]byte(val), &b); err != nil {
return nil, errors.Wrap(err, "unmarshaling bundle")
}
return &b, nil
}
Loading

0 comments on commit 34d0838

Please sign in to comment.