fix(deps): update module github.com/containers/image/v5 to v5.34.1

Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
This commit is contained in:
renovate[bot] 2025-02-28 22:12:18 +00:00 committed by GitHub
parent 2d79fec20c
commit 8a44fe6c8b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 412 additions and 28 deletions

2
go.mod
View File

@ -8,7 +8,7 @@ go 1.22.8
require (
github.com/Masterminds/semver/v3 v3.3.1
github.com/containers/common v0.62.0
github.com/containers/image/v5 v5.34.0
github.com/containers/image/v5 v5.34.1
github.com/containers/ocicrypt v1.2.1
github.com/containers/storage v1.57.1
github.com/docker/distribution v2.8.3+incompatible

4
go.sum
View File

@ -43,8 +43,8 @@ github.com/containerd/typeurl/v2 v2.2.3 h1:yNA/94zxWdvYACdYO8zofhrTVuQY73fFU1y++
github.com/containerd/typeurl/v2 v2.2.3/go.mod h1:95ljDnPfD3bAbDJRugOiShd/DlAAsxGtUBhJxIn7SCk=
github.com/containers/common v0.62.0 h1:Sl9WE5h7Y/F3bejrMAA4teP1EcY9ygqJmW4iwSloZ10=
github.com/containers/common v0.62.0/go.mod h1:Yec+z8mrSq4rydHofrnDCBqAcNA/BGrSg1kfFUL6F6s=
github.com/containers/image/v5 v5.34.0 h1:HPqQaDUsox/3mC1pbOyLAIQEp0JhQqiUZ+6JiFIZLDI=
github.com/containers/image/v5 v5.34.0/go.mod h1:/WnvUSEfdqC/ahMRd4YJDBLrpYWkGl018rB77iB3FDo=
github.com/containers/image/v5 v5.34.1 h1:/m2bkFnuedTyNkzma8s7cFLjeefPIb4trjyafWhIlwM=
github.com/containers/image/v5 v5.34.1/go.mod h1:/WnvUSEfdqC/ahMRd4YJDBLrpYWkGl018rB77iB3FDo=
github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01 h1:Qzk5C6cYglewc+UyGf6lc8Mj2UaPTHy/iF2De0/77CA=
github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01/go.mod h1:9rfv8iPl1ZP7aqh9YA68wnZv2NUDbXdcdPHVz0pFbPY=
github.com/containers/ocicrypt v1.2.1 h1:0qIOTT9DoYwcKmxSt8QJt+VzMY18onl9jUXsxpVhSmM=

View File

@ -108,19 +108,10 @@ func (f *fulcioTrustRoot) verifyFulcioCertificateAtTime(relevantTime time.Time,
}
}
untrustedLeafCerts, err := cryptoutils.UnmarshalCertificatesFromPEM(untrustedCertificateBytes)
untrustedCertificate, err := parseLeafCertFromPEM(untrustedCertificateBytes)
if err != nil {
return nil, internal.NewInvalidSignatureError(fmt.Sprintf("parsing leaf certificate: %v", err))
return nil, err
}
switch len(untrustedLeafCerts) {
case 0:
return nil, internal.NewInvalidSignatureError("no certificate found in signature certificate data")
case 1:
break // OK
default:
return nil, internal.NewInvalidSignatureError("unexpected multiple certificates present in signature certificate data")
}
untrustedCertificate := untrustedLeafCerts[0]
// Go rejects Subject Alternative Name that has no DNSNames, EmailAddresses, IPAddresses and URIs;
// we match SAN ourselves, so override that.
@ -195,6 +186,21 @@ func (f *fulcioTrustRoot) verifyFulcioCertificateAtTime(relevantTime time.Time,
return untrustedCertificate.PublicKey, nil
}
func parseLeafCertFromPEM(untrustedCertificateBytes []byte) (*x509.Certificate, error) {
untrustedLeafCerts, err := cryptoutils.UnmarshalCertificatesFromPEM(untrustedCertificateBytes)
if err != nil {
return nil, internal.NewInvalidSignatureError(fmt.Sprintf("parsing leaf certificate: %v", err))
}
switch len(untrustedLeafCerts) {
case 0:
return nil, internal.NewInvalidSignatureError("no certificate found in signature certificate data")
case 1: // OK
return untrustedLeafCerts[0], nil
default:
return nil, internal.NewInvalidSignatureError("unexpected multiple certificates present in signature certificate data")
}
}
func verifyRekorFulcio(rekorPublicKeys []*ecdsa.PublicKey, fulcioTrustRoot *fulcioTrustRoot, untrustedRekorSET []byte,
untrustedCertificateBytes []byte, untrustedIntermediateChainBytes []byte, untrustedBase64Signature string,
untrustedPayloadBytes []byte) (crypto.PublicKey, error) {

View File

@ -0,0 +1,74 @@
package signature
import (
"crypto"
"crypto/x509"
"errors"
"fmt"
"slices"
"github.com/containers/image/v5/signature/internal"
"github.com/sigstore/sigstore/pkg/cryptoutils"
)
type pkiTrustRoot struct {
caRootsCertificates *x509.CertPool
caIntermediateCertificates *x509.CertPool
subjectEmail string
subjectHostname string
}
func (p *pkiTrustRoot) validate() error {
if p.subjectEmail == "" && p.subjectHostname == "" {
return errors.New("Internal inconsistency: PKI use set up without subject email or subject hostname")
}
return nil
}
func verifyPKI(pkiTrustRoot *pkiTrustRoot, untrustedCertificateBytes []byte, untrustedIntermediateChainBytes []byte) (crypto.PublicKey, error) {
var untrustedIntermediatePool *x509.CertPool
if pkiTrustRoot.caIntermediateCertificates != nil {
untrustedIntermediatePool = pkiTrustRoot.caIntermediateCertificates.Clone()
} else {
untrustedIntermediatePool = x509.NewCertPool()
}
if len(untrustedIntermediateChainBytes) > 0 {
untrustedIntermediateChain, err := cryptoutils.UnmarshalCertificatesFromPEM(untrustedIntermediateChainBytes)
if err != nil {
return nil, internal.NewInvalidSignatureError(fmt.Sprintf("loading certificate chain: %v", err))
}
if len(untrustedIntermediateChain) > 1 {
for _, untrustedIntermediateCert := range untrustedIntermediateChain[:len(untrustedIntermediateChain)-1] {
untrustedIntermediatePool.AddCert(untrustedIntermediateCert)
}
}
}
untrustedCertificate, err := parseLeafCertFromPEM(untrustedCertificateBytes)
if err != nil {
return nil, err
}
if _, err := untrustedCertificate.Verify(x509.VerifyOptions{
Intermediates: untrustedIntermediatePool,
Roots: pkiTrustRoot.caRootsCertificates,
KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageCodeSigning},
}); err != nil {
return nil, internal.NewInvalidSignatureError(fmt.Sprintf("veryfing leaf certificate failed: %v", err))
}
if pkiTrustRoot.subjectEmail != "" {
if !slices.Contains(untrustedCertificate.EmailAddresses, pkiTrustRoot.subjectEmail) {
return nil, internal.NewInvalidSignatureError(fmt.Sprintf("Required email %q not found (got %q)",
pkiTrustRoot.subjectEmail,
untrustedCertificate.EmailAddresses))
}
}
if pkiTrustRoot.subjectHostname != "" {
if err = untrustedCertificate.VerifyHostname(pkiTrustRoot.subjectHostname); err != nil {
return nil, internal.NewInvalidSignatureError(fmt.Sprintf("Unexpected subject hostname: %v", err))
}
}
return untrustedCertificate.PublicKey, nil
}

View File

@ -71,6 +71,17 @@ func PRSigstoreSignedWithFulcio(fulcio PRSigstoreSignedFulcio) PRSigstoreSignedO
}
}
// PRSigstoreSignedWithPKI specifies a value for the "pki" field when calling NewPRSigstoreSigned.
func PRSigstoreSignedWithPKI(p PRSigstoreSignedPKI) PRSigstoreSignedOption {
return func(pr *prSigstoreSigned) error {
if pr.PKI != nil {
return InvalidPolicyFormatError(`"pki" already specified`)
}
pr.PKI = p
return nil
}
}
// PRSigstoreSignedWithRekorPublicKeyPath specifies a value for the "rekorPublicKeyPath" field when calling NewPRSigstoreSigned.
func PRSigstoreSignedWithRekorPublicKeyPath(rekorPublicKeyPath string) PRSigstoreSignedOption {
return func(pr *prSigstoreSigned) error {
@ -159,8 +170,11 @@ func newPRSigstoreSigned(options ...PRSigstoreSignedOption) (*prSigstoreSigned,
if res.Fulcio != nil {
keySources++
}
if res.PKI != nil {
keySources++
}
if keySources != 1 {
return nil, InvalidPolicyFormatError("exactly one of keyPath, keyPaths, keyData, keyDatas and fulcio must be specified")
return nil, InvalidPolicyFormatError("exactly one of keyPath, keyPaths, keyData, keyDatas, fulcio, and pki must be specified")
}
rekorSources := 0
@ -182,6 +196,9 @@ func newPRSigstoreSigned(options ...PRSigstoreSignedOption) (*prSigstoreSigned,
if res.Fulcio != nil && rekorSources == 0 {
return nil, InvalidPolicyFormatError("At least one of rekorPublickeyPath, rekorPublicKeyPaths, rekorPublickeyData and rekorPublicKeyDatas must be specified if fulcio is used")
}
if res.PKI != nil && rekorSources > 0 {
return nil, InvalidPolicyFormatError("rekorPublickeyPath, rekorPublicKeyPaths, rekorPublickeyData and rekorPublicKeyDatas are not supported for pki")
}
if res.SignedIdentity == nil {
return nil, InvalidPolicyFormatError("signedIdentity not specified")
@ -218,9 +235,10 @@ var _ json.Unmarshaler = (*prSigstoreSigned)(nil)
func (pr *prSigstoreSigned) UnmarshalJSON(data []byte) error {
*pr = prSigstoreSigned{}
var tmp prSigstoreSigned
var gotKeyPath, gotKeyPaths, gotKeyData, gotKeyDatas, gotFulcio bool
var gotKeyPath, gotKeyPaths, gotKeyData, gotKeyDatas, gotFulcio, gotPKI bool
var gotRekorPublicKeyPath, gotRekorPublicKeyPaths, gotRekorPublicKeyData, gotRekorPublicKeyDatas bool
var fulcio prSigstoreSignedFulcio
var pki prSigstoreSignedPKI
var signedIdentity json.RawMessage
if err := internal.ParanoidUnmarshalJSONObject(data, func(key string) any {
switch key {
@ -253,6 +271,9 @@ func (pr *prSigstoreSigned) UnmarshalJSON(data []byte) error {
case "rekorPublicKeyDatas":
gotRekorPublicKeyDatas = true
return &tmp.RekorPublicKeyDatas
case "pki":
gotPKI = true
return &pki
case "signedIdentity":
return &signedIdentity
default:
@ -303,6 +324,9 @@ func (pr *prSigstoreSigned) UnmarshalJSON(data []byte) error {
if gotRekorPublicKeyDatas {
opts = append(opts, PRSigstoreSignedWithRekorPublicKeyDatas(tmp.RekorPublicKeyDatas))
}
if gotPKI {
opts = append(opts, PRSigstoreSignedWithPKI(&pki))
}
opts = append(opts, PRSigstoreSignedWithSignedIdentity(tmp.SignedIdentity))
res, err := newPRSigstoreSigned(opts...)
@ -440,3 +464,167 @@ func (f *prSigstoreSignedFulcio) UnmarshalJSON(data []byte) error {
*f = *res
return nil
}
// PRSigstoreSignedPKIOption is a way to pass values to NewPRSigstoreSignedPKI
type PRSigstoreSignedPKIOption func(*prSigstoreSignedPKI) error
// PRSigstoreSignedPKIWithCARootsPath specifies a value for the "caRootsPath" field when calling NewPRSigstoreSignedPKI
func PRSigstoreSignedPKIWithCARootsPath(caRootsPath string) PRSigstoreSignedPKIOption {
return func(p *prSigstoreSignedPKI) error {
if p.CARootsPath != "" {
return InvalidPolicyFormatError(`"caRootsPath" already specified`)
}
p.CARootsPath = caRootsPath
return nil
}
}
// PRSigstoreSignedPKIWithCARootsData specifies a value for the "caRootsData" field when calling NewPRSigstoreSignedPKI
func PRSigstoreSignedPKIWithCARootsData(caRootsData []byte) PRSigstoreSignedPKIOption {
return func(p *prSigstoreSignedPKI) error {
if p.CARootsData != nil {
return InvalidPolicyFormatError(`"caRootsData" already specified`)
}
p.CARootsData = caRootsData
return nil
}
}
// PRSigstoreSignedPKIWithCAIntermediatesPath specifies a value for the "caIntermediatesPath" field when calling NewPRSigstoreSignedPKI
func PRSigstoreSignedPKIWithCAIntermediatesPath(caIntermediatesPath string) PRSigstoreSignedPKIOption {
return func(p *prSigstoreSignedPKI) error {
if p.CAIntermediatesPath != "" {
return InvalidPolicyFormatError(`"caIntermediatesPath" already specified`)
}
p.CAIntermediatesPath = caIntermediatesPath
return nil
}
}
// PRSigstoreSignedPKIWithCAIntermediatesData specifies a value for the "caIntermediatesData" field when calling NewPRSigstoreSignedPKI
func PRSigstoreSignedPKIWithCAIntermediatesData(caIntermediatesData []byte) PRSigstoreSignedPKIOption {
return func(p *prSigstoreSignedPKI) error {
if p.CAIntermediatesData != nil {
return InvalidPolicyFormatError(`"caIntermediatesData" already specified`)
}
p.CAIntermediatesData = caIntermediatesData
return nil
}
}
// PRSigstoreSignedPKIWithSubjectEmail specifies a value for the "subjectEmail" field when calling NewPRSigstoreSignedPKI
func PRSigstoreSignedPKIWithSubjectEmail(subjectEmail string) PRSigstoreSignedPKIOption {
return func(p *prSigstoreSignedPKI) error {
if p.SubjectEmail != "" {
return InvalidPolicyFormatError(`"subjectEmail" already specified`)
}
p.SubjectEmail = subjectEmail
return nil
}
}
// PRSigstoreSignedPKIWithSubjectHostname specifies a value for the "subjectHostname" field when calling NewPRSigstoreSignedPKI
func PRSigstoreSignedPKIWithSubjectHostname(subjectHostname string) PRSigstoreSignedPKIOption {
return func(p *prSigstoreSignedPKI) error {
if p.SubjectHostname != "" {
return InvalidPolicyFormatError(`"subjectHostname" already specified`)
}
p.SubjectHostname = subjectHostname
return nil
}
}
// newPRSigstoreSignedPKI is NewPRSigstoreSignedPKI, except it returns the private type
func newPRSigstoreSignedPKI(options ...PRSigstoreSignedPKIOption) (*prSigstoreSignedPKI, error) {
res := prSigstoreSignedPKI{}
for _, o := range options {
if err := o(&res); err != nil {
return nil, err
}
}
if res.CARootsPath != "" && res.CARootsData != nil {
return nil, InvalidPolicyFormatError("caRootsPath and caRootsData cannot be used simultaneously")
}
if res.CARootsPath == "" && res.CARootsData == nil {
return nil, InvalidPolicyFormatError("At least one of caRootsPath and caRootsData must be specified")
}
if res.CAIntermediatesPath != "" && res.CAIntermediatesData != nil {
return nil, InvalidPolicyFormatError("caIntermediatesPath and caIntermediatesData cannot be used simultaneously")
}
if res.SubjectEmail == "" && res.SubjectHostname == "" {
return nil, InvalidPolicyFormatError("At least one of subjectEmail, subjectHostname must be specified")
}
return &res, nil
}
// NewPRSigstoreSignedPKI returns a PRSigstoreSignedPKI based on options.
func NewPRSigstoreSignedPKI(options ...PRSigstoreSignedPKIOption) (PRSigstoreSignedPKI, error) {
return newPRSigstoreSignedPKI(options...)
}
// Compile-time check that prSigstoreSignedPKI implements json.Unmarshaler.
var _ json.Unmarshaler = (*prSigstoreSignedPKI)(nil)
func (p *prSigstoreSignedPKI) UnmarshalJSON(data []byte) error {
*p = prSigstoreSignedPKI{}
var tmp prSigstoreSignedPKI
var gotCARootsPath, gotCARootsData, gotCAIntermediatesPath, gotCAIntermediatesData, gotSubjectEmail, gotSubjectHostname bool
if err := internal.ParanoidUnmarshalJSONObject(data, func(key string) any {
switch key {
case "caRootsPath":
gotCARootsPath = true
return &tmp.CARootsPath
case "caRootsData":
gotCARootsData = true
return &tmp.CARootsData
case "caIntermediatesPath":
gotCAIntermediatesPath = true
return &tmp.CAIntermediatesPath
case "caIntermediatesData":
gotCAIntermediatesData = true
return &tmp.CAIntermediatesData
case "subjectEmail":
gotSubjectEmail = true
return &tmp.SubjectEmail
case "subjectHostname":
gotSubjectHostname = true
return &tmp.SubjectHostname
default:
return nil
}
}); err != nil {
return err
}
var opts []PRSigstoreSignedPKIOption
if gotCARootsPath {
opts = append(opts, PRSigstoreSignedPKIWithCARootsPath(tmp.CARootsPath))
}
if gotCARootsData {
opts = append(opts, PRSigstoreSignedPKIWithCARootsData(tmp.CARootsData))
}
if gotCAIntermediatesPath {
opts = append(opts, PRSigstoreSignedPKIWithCAIntermediatesPath(tmp.CAIntermediatesPath))
}
if gotCAIntermediatesData {
opts = append(opts, PRSigstoreSignedPKIWithCAIntermediatesData(tmp.CAIntermediatesData))
}
if gotSubjectEmail {
opts = append(opts, PRSigstoreSignedPKIWithSubjectEmail(tmp.SubjectEmail))
}
if gotSubjectHostname {
opts = append(opts, PRSigstoreSignedPKIWithSubjectHostname(tmp.SubjectHostname))
}
res, err := newPRSigstoreSignedPKI(opts...)
if err != nil {
return err
}
*p = *res
return nil
}

View File

@ -97,11 +97,64 @@ func (f *prSigstoreSignedFulcio) prepareTrustRoot() (*fulcioTrustRoot, error) {
return &fulcio, nil
}
// prepareTrustRoot creates a pkiTrustRoot from the input data.
// (This also prevents external implementations of this interface, ensuring that prSigstoreSignedPKI is the only one.)
func (p *prSigstoreSignedPKI) prepareTrustRoot() (*pkiTrustRoot, error) {
caRootsCertPEMs, err := loadBytesFromConfigSources(configBytesSources{
inconsistencyErrorMessage: `Internal inconsistency: both "caRootsPath" and "caRootsData" specified`,
path: p.CARootsPath,
data: p.CARootsData,
})
if err != nil {
return nil, err
}
if len(caRootsCertPEMs) != 1 {
return nil, errors.New(`Internal inconsistency: PKI specified with not exactly one of "caRootsPath" nor "caRootsData"`)
}
rootsCerts := x509.NewCertPool()
if ok := rootsCerts.AppendCertsFromPEM(caRootsCertPEMs[0]); !ok {
return nil, errors.New("error loading PKI CA Roots certificates")
}
pki := pkiTrustRoot{
caRootsCertificates: rootsCerts,
subjectEmail: p.SubjectEmail,
subjectHostname: p.SubjectHostname,
}
caIntermediateCertPEMs, err := loadBytesFromConfigSources(configBytesSources{
inconsistencyErrorMessage: `Internal inconsistency: both "caIntermediatesPath" and "caIntermediatesData" specified`,
path: p.CAIntermediatesPath,
data: p.CAIntermediatesData,
})
if err != nil {
return nil, err
}
if caIntermediateCertPEMs != nil {
if len(caIntermediateCertPEMs) != 1 {
return nil, errors.New(`Internal inconsistency: PKI specified with invalid value from "caIntermediatesPath" or "caIntermediatesData"`)
}
intermediatePool := x509.NewCertPool()
trustedIntermediates, err := cryptoutils.UnmarshalCertificatesFromPEM(caIntermediateCertPEMs[0])
if err != nil {
return nil, internal.NewInvalidSignatureError(fmt.Sprintf("loading trusted intermediate certificates: %v", err))
}
for _, trustedIntermediateCert := range trustedIntermediates {
intermediatePool.AddCert(trustedIntermediateCert)
}
pki.caIntermediateCertificates = intermediatePool
}
if err := pki.validate(); err != nil {
return nil, err
}
return &pki, nil
}
// sigstoreSignedTrustRoot contains an already parsed version of the prSigstoreSigned policy
type sigstoreSignedTrustRoot struct {
publicKeys []crypto.PublicKey
fulcio *fulcioTrustRoot
rekorPublicKeys []*ecdsa.PublicKey
pki *pkiTrustRoot
}
func (pr *prSigstoreSigned) prepareTrustRoot() (*sigstoreSignedTrustRoot, error) {
@ -166,6 +219,14 @@ func (pr *prSigstoreSigned) prepareTrustRoot() (*sigstoreSignedTrustRoot, error)
}
}
if pr.PKI != nil {
p, err := pr.PKI.prepareTrustRoot()
if err != nil {
return nil, err
}
res.pki = p
}
return &res, nil
}
@ -189,13 +250,23 @@ func (pr *prSigstoreSigned) isSignatureAccepted(ctx context.Context, image priva
}
untrustedPayload := sig.UntrustedPayload()
keySources := 0
if trustRoot.publicKeys != nil {
keySources++
}
if trustRoot.fulcio != nil {
keySources++
}
if trustRoot.pki != nil {
keySources++
}
var publicKeys []crypto.PublicKey
switch {
case trustRoot.publicKeys != nil && trustRoot.fulcio != nil: // newPRSigstoreSigned rejects such combinations.
return sarRejected, errors.New("Internal inconsistency: Both a public key and Fulcio CA specified")
case trustRoot.publicKeys == nil && trustRoot.fulcio == nil: // newPRSigstoreSigned rejects such combinations.
return sarRejected, errors.New("Internal inconsistency: Neither a public key nor a Fulcio CA specified")
case keySources > 1: // newPRSigstoreSigned rejects more than one key sources.
return sarRejected, errors.New("Internal inconsistency: More than one of public key, Fulcio, or PKI specified")
case keySources == 0: // newPRSigstoreSigned rejects empty key sources.
return sarRejected, errors.New("Internal inconsistency: A public key, Fulcio, or PKI must be specified.")
case trustRoot.publicKeys != nil:
if trustRoot.rekorPublicKeys != nil {
untrustedSET, ok := untrustedAnnotations[signature.SigstoreSETAnnotationKey]
@ -254,6 +325,24 @@ func (pr *prSigstoreSigned) isSignatureAccepted(ctx context.Context, image priva
return sarRejected, err
}
publicKeys = []crypto.PublicKey{pk}
case trustRoot.pki != nil:
if trustRoot.rekorPublicKeys != nil { // newPRSigstoreSigned rejects such combinations.
return sarRejected, errors.New("Internal inconsistency: PKI specified with a Rekor public key")
}
untrustedCert, ok := untrustedAnnotations[signature.SigstoreCertificateAnnotationKey]
if !ok {
return sarRejected, fmt.Errorf("missing %s annotation", signature.SigstoreCertificateAnnotationKey)
}
var untrustedIntermediateChainBytes []byte
if untrustedIntermediateChain, ok := untrustedAnnotations[signature.SigstoreIntermediateCertificateChainAnnotationKey]; ok {
untrustedIntermediateChainBytes = []byte(untrustedIntermediateChain)
}
pk, err := verifyPKI(trustRoot.pki, []byte(untrustedCert), untrustedIntermediateChainBytes)
if err != nil {
return sarRejected, err
}
publicKeys = []crypto.PublicKey{pk}
}
if len(publicKeys) == 0 {

View File

@ -111,16 +111,16 @@ type prSignedBaseLayer struct {
type prSigstoreSigned struct {
prCommon
// KeyPath is a pathname to a local file containing the trusted key. Exactly one of KeyPath, KeyPaths, KeyData, KeyDatas and Fulcio must be specified.
// KeyPath is a pathname to a local file containing the trusted key. Exactly one of KeyPath, KeyPaths, KeyData, KeyDatas, Fulcio, and PKI must be specified.
KeyPath string `json:"keyPath,omitempty"`
// KeyPaths is a set of pathnames to local files containing the trusted key(s). Exactly one of KeyPath, KeyPaths, KeyData, KeyDatas and Fulcio must be specified.
// KeyPaths is a set of pathnames to local files containing the trusted key(s). Exactly one of KeyPath, KeyPaths, KeyData, KeyDatas, Fulcio, and PKI must be specified.
KeyPaths []string `json:"keyPaths,omitempty"`
// KeyData contains the trusted key, base64-encoded. Exactly one of KeyPath, KeyPaths, KeyData, KeyDatas and Fulcio must be specified.
// KeyData contains the trusted key, base64-encoded. Exactly one of KeyPath, KeyPaths, KeyData, KeyDatas, Fulcio, and PKI must be specified.
KeyData []byte `json:"keyData,omitempty"`
// KeyDatas is a set of trusted keys, base64-encoded. Exactly one of KeyPath, KeyPaths, KeyData, KeyDatas and Fulcio must be specified.
// KeyDatas is a set of trusted keys, base64-encoded. Exactly one of KeyPath, KeyPaths, KeyData, KeyDatas, Fulcio, and PKI must be specified.
KeyDatas [][]byte `json:"keyDatas,omitempty"`
// Fulcio specifies which Fulcio-generated certificates are accepted. Exactly one of KeyPath, KeyPaths, KeyData, KeyDatas and Fulcio must be specified.
// Fulcio specifies which Fulcio-generated certificates are accepted. Exactly one of KeyPath, KeyPaths, KeyData, KeyDatas, Fulcio, and PKI must be specified.
// If Fulcio is specified, one of RekorPublicKeyPath or RekorPublicKeyData must be specified as well.
Fulcio PRSigstoreSignedFulcio `json:"fulcio,omitempty"`
@ -141,6 +141,9 @@ type prSigstoreSigned struct {
// otherwise it is optional (and Rekor inclusion is not required if a Rekor public key is not specified).
RekorPublicKeyDatas [][]byte `json:"rekorPublicKeyDatas,omitempty"`
// PKI specifies which PKI-generated certificates are accepted. Exactly one of KeyPath, KeyPaths, KeyData, KeyDatas, Fulcio, and PKI must be specified.
PKI PRSigstoreSignedPKI `json:"pki,omitempty"`
// SignedIdentity specifies what image identity the signature must be claiming about the image.
// Defaults to "matchRepoDigestOrExact" if not specified.
// Note that /usr/bin/cosign interoperability might require using repo-only matching.
@ -167,6 +170,30 @@ type prSigstoreSignedFulcio struct {
SubjectEmail string `json:"subjectEmail,omitempty"`
}
// PRSigstoreSignedPKI contains PKI configuration options for a "sigstoreSigned" PolicyRequirement.
type PRSigstoreSignedPKI interface {
// prepareTrustRoot creates a pkiTrustRoot from the input data.
// (This also prevents external implementations of this interface, ensuring that prSigstoreSignedPKI is the only one.)
prepareTrustRoot() (*pkiTrustRoot, error)
}
// prSigstoreSignedPKI contains non-fulcio certificate PKI configuration options for prSigstoreSigned
type prSigstoreSignedPKI struct {
// CARootsPath a path to a file containing accepted CA root certificates, in PEM format. Exactly one of CARootsPath and CARootsData must be specified.
CARootsPath string `json:"caRootsPath"`
// CARootsData contains accepted CA root certificates in PEM format, all of that base64-encoded. Exactly one of CARootsPath and CARootsData must be specified.
CARootsData []byte `json:"caRootsData"`
// CAIntermediatesPath a path to a file containing accepted CA intermediate certificates, in PEM format. Only one of CAIntermediatesPath or CAIntermediatesData can be specified, not both.
CAIntermediatesPath string `json:"caIntermediatesPath"`
// CAIntermediatesData contains accepted CA intermediate certificates in PEM format, all of that base64-encoded. Only one of CAIntermediatesPath or CAIntermediatesData can be specified, not both.
CAIntermediatesData []byte `json:"caIntermediatesData"`
// SubjectEmail specifies the expected email address imposed on the subject to which the certificate was issued. At least one of SubjectEmail and SubjectHostname must be specified.
SubjectEmail string `json:"subjectEmail"`
// SubjectHostname specifies the expected hostname imposed on the subject to which the certificate was issued. At least one of SubjectEmail and SubjectHostname must be specified.
SubjectHostname string `json:"subjectHostname"`
}
// PolicyReferenceMatch specifies a set of image identities accepted in PolicyRequirement.
// The type is public, but its implementation is private.

View File

@ -8,7 +8,7 @@ const (
// VersionMinor is for functionality in a backwards-compatible manner
VersionMinor = 34
// VersionPatch is for backwards-compatible bug fixes
VersionPatch = 0
VersionPatch = 1
// VersionDev indicates development branch. Releases will be empty string.
VersionDev = ""

2
vendor/modules.txt vendored
View File

@ -81,7 +81,7 @@ github.com/containers/common/pkg/password
github.com/containers/common/pkg/report
github.com/containers/common/pkg/report/camelcase
github.com/containers/common/pkg/retry
# github.com/containers/image/v5 v5.34.0
# github.com/containers/image/v5 v5.34.1
## explicit; go 1.22.8
github.com/containers/image/v5/copy
github.com/containers/image/v5/directory