Compare commits
10 Commits
Author | SHA1 | Date |
---|---|---|
|
d5d9d35f23 | |
|
7ff3986456 | |
|
b347de6d9b | |
|
1c4d858794 | |
|
9347a39c27 | |
|
717fb39c46 | |
|
e6acd4302c | |
|
7dbd71040a | |
|
ba57a9fe92 | |
|
4c0c3f0b97 |
|
@ -6,7 +6,7 @@ env:
|
|||
#### Global variables used for all tasks
|
||||
####
|
||||
# Name of the ultimate destination branch for this CI run, PR or post-merge.
|
||||
DEST_BRANCH: "main"
|
||||
DEST_BRANCH: "release-1.39"
|
||||
GOPATH: "/var/tmp/go"
|
||||
GOSRC: "${GOPATH}/src/github.com/containers/buildah"
|
||||
GOCACHE: "/tmp/go-build"
|
||||
|
|
|
@ -2,6 +2,15 @@
|
|||
|
||||
# Changelog
|
||||
|
||||
## v1.39.2 (2025-03-03)
|
||||
|
||||
[release-1.39] Bump c/image to v5.34.1, c/common v0.62.1
|
||||
|
||||
## v1.39.1 (2025-02-25)
|
||||
|
||||
chroot createPlatformContainer: use MS_REMOUNT
|
||||
chore(deps): update module github.com/go-jose/go-jose/v4 to v4.0.5 [security]
|
||||
|
||||
## v1.39.0 (2025-01-31)
|
||||
|
||||
Bump c/storage v1.57.1, c/image 5.34.0, c/common v0.62.0
|
||||
|
|
|
@ -1,3 +1,11 @@
|
|||
- Changelog for v1.39.2 (2025-03-03)
|
||||
* [release-1.39] Bump c/image to v5.34.1, c/common v0.62.1
|
||||
|
||||
- Changelog for v1.39.1 (2025-02-25)
|
||||
|
||||
* chroot createPlatformContainer: use MS_REMOUNT
|
||||
* chore(deps): update module github.com/go-jose/go-jose/v4 to v4.0.5 [security]
|
||||
|
||||
- Changelog for v1.39.0 (2025-01-31)
|
||||
* Bump c/storage v1.57.1, c/image 5.34.0, c/common v0.62.0
|
||||
* Update module github.com/containers/storage to v1.57.0
|
||||
|
|
|
@ -263,7 +263,7 @@ func createPlatformContainer(options runUsingChrootExecSubprocOptions) error {
|
|||
return fmt.Errorf("changing to host root directory: %w", err)
|
||||
}
|
||||
// make sure we only unmount things under this tree
|
||||
if err := unix.Mount(".", ".", "bind", unix.MS_BIND|unix.MS_SLAVE|unix.MS_REC, ""); err != nil {
|
||||
if err := unix.Mount(".", ".", "bind", unix.MS_REMOUNT|unix.MS_BIND|unix.MS_SLAVE|unix.MS_REC, ""); err != nil {
|
||||
return fmt.Errorf("tweaking mount flags on host root directory before unmounting from mount namespace: %w", err)
|
||||
}
|
||||
// detach this (unnamed?) old directory
|
||||
|
|
|
@ -29,7 +29,7 @@ const (
|
|||
// identify working containers.
|
||||
Package = "buildah"
|
||||
// Version for the Package. Also used by .packit.sh for Packit builds.
|
||||
Version = "1.39.0"
|
||||
Version = "1.39.2"
|
||||
|
||||
// DefaultRuntime if containers.conf fails.
|
||||
DefaultRuntime = "runc"
|
||||
|
|
6
go.mod
6
go.mod
|
@ -7,8 +7,8 @@ go 1.22.8
|
|||
require (
|
||||
github.com/containerd/platforms v1.0.0-rc.1
|
||||
github.com/containernetworking/cni v1.2.3
|
||||
github.com/containers/common v0.62.0
|
||||
github.com/containers/image/v5 v5.34.0
|
||||
github.com/containers/common v0.62.1
|
||||
github.com/containers/image/v5 v5.34.1
|
||||
github.com/containers/luksy v0.0.0-20250106202729-a3a812db5b72
|
||||
github.com/containers/ocicrypt v1.2.1
|
||||
github.com/containers/storage v1.57.1
|
||||
|
@ -71,7 +71,7 @@ require (
|
|||
github.com/docker/docker-credential-helpers v0.8.2 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/fsnotify/fsnotify v1.8.0 // indirect
|
||||
github.com/go-jose/go-jose/v4 v4.0.4 // indirect
|
||||
github.com/go-jose/go-jose/v4 v4.0.5 // indirect
|
||||
github.com/go-logr/logr v1.4.2 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-openapi/analysis v0.23.0 // indirect
|
||||
|
|
12
go.sum
12
go.sum
|
@ -63,10 +63,10 @@ github.com/containernetworking/cni v1.2.3 h1:hhOcjNVUQTnzdRJ6alC5XF+wd9mfGIUaj8F
|
|||
github.com/containernetworking/cni v1.2.3/go.mod h1:DuLgF+aPd3DzcTQTtp/Nvl1Kim23oFKdm2okJzBQA5M=
|
||||
github.com/containernetworking/plugins v1.5.1 h1:T5ji+LPYjjgW0QM+KyrigZbLsZ8jaX+E5J/EcKOE4gQ=
|
||||
github.com/containernetworking/plugins v1.5.1/go.mod h1:MIQfgMayGuHYs0XdNudf31cLLAC+i242hNm6KuDGqCM=
|
||||
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/common v0.62.1 h1:durvu7Kelb8PYgX7bwuAg/d5LKj2hs3cAaqcU7Vnqus=
|
||||
github.com/containers/common v0.62.1/go.mod h1:n9cEboBmY3AnTk1alkq4t7sLM4plwkDCiaWbsf67YxE=
|
||||
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/luksy v0.0.0-20250106202729-a3a812db5b72 h1:hdBIFaml6hO+Bal8CdQSQPTF305gwsJfubs4NoOV53A=
|
||||
|
@ -116,8 +116,8 @@ github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/
|
|||
github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||
github.com/fsouza/go-dockerclient v1.12.0 h1:S2f2crEUbBNCFiF06kR/GvioEB8EMsb3Td/bpawD+aU=
|
||||
github.com/fsouza/go-dockerclient v1.12.0/go.mod h1:YWUtjg8japrqD/80L98nTtCoxQFp5B5wrSsnyeB5lFo=
|
||||
github.com/go-jose/go-jose/v4 v4.0.4 h1:VsjPI33J0SB9vQM6PLmNjoHqMQNGPiZ0rHL7Ni7Q6/E=
|
||||
github.com/go-jose/go-jose/v4 v4.0.4/go.mod h1:NKb5HO1EZccyMpiZNbdUw/14tiXNyUJh188dfnMCAfc=
|
||||
github.com/go-jose/go-jose/v4 v4.0.5 h1:M6T8+mKZl/+fNNuFHvGIzDz7BTLQPIounk/b9dw3AaE=
|
||||
github.com/go-jose/go-jose/v4 v4.0.5/go.mod h1:s3P1lRrkT8igV8D9OjyL4WRyHvjB6a4JSllnOrmmBOA=
|
||||
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
FROM mirror.gcr.io/busybox
|
||||
ADD https://github.com/openshift/origin/raw/master/README.md README.md
|
||||
ADD https://github.com/openshift/origin/raw/main/README.md README.md
|
||||
USER 1001
|
||||
ADD https://github.com/openshift/origin/raw/master/LICENSE .
|
||||
ADD https://github.com/openshift/origin/raw/master/LICENSE A
|
||||
ADD https://github.com/openshift/origin/raw/master/LICENSE ./a
|
||||
ADD https://github.com/openshift/origin/raw/main/LICENSE .
|
||||
ADD https://github.com/openshift/origin/raw/main/LICENSE A
|
||||
ADD https://github.com/openshift/origin/raw/main/LICENSE ./a
|
||||
USER root
|
||||
RUN mkdir ./b
|
||||
ADD https://github.com/openshift/origin/raw/master/LICENSE ./b/a
|
||||
ADD https://github.com/openshift/origin/raw/master/LICENSE ./b/.
|
||||
ADD https://github.com/openshift/origin/raw/main/LICENSE ./b/a
|
||||
ADD https://github.com/openshift/origin/raw/main/LICENSE ./b/.
|
||||
ADD https://github.com/openshift/ruby-hello-world/archive/master.zip /tmp/
|
||||
|
|
|
@ -997,3 +997,23 @@ _EOF
|
|||
run_buildah ? bud --pull=false --layers .
|
||||
expect_output --substring -- "-c requires an argument"
|
||||
}
|
||||
|
||||
@test "root fs only mounted once" {
|
||||
if test `uname` != Linux ; then
|
||||
skip "not meaningful except on Linux"
|
||||
fi
|
||||
_prefetch busybox
|
||||
run_buildah from --pull=never --quiet busybox
|
||||
cid="$output"
|
||||
run_buildah run $cid cat /proc/self/mountinfo
|
||||
echo "$output" > ${TEST_SCRATCH_DIR}/mountinfo1
|
||||
echo "# mountinfo unfiltered:"
|
||||
cat ${TEST_SCRATCH_DIR}/mountinfo1
|
||||
grep ' / rw,' ${TEST_SCRATCH_DIR}/mountinfo1 > ${TEST_SCRATCH_DIR}/mountinfo2
|
||||
echo "# mountinfo grepped:"
|
||||
cat ${TEST_SCRATCH_DIR}/mountinfo2
|
||||
wc -l < ${TEST_SCRATCH_DIR}/mountinfo2 > ${TEST_SCRATCH_DIR}/mountinfo3
|
||||
echo "# mountinfo count:"
|
||||
cat ${TEST_SCRATCH_DIR}/mountinfo3
|
||||
assert $(cat ${TEST_SCRATCH_DIR}/mountinfo3) -eq 1
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package version
|
||||
|
||||
// Version is the version of the build.
|
||||
const Version = "0.62.0"
|
||||
const Version = "0.62.1"
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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 = ""
|
||||
|
|
|
@ -7,9 +7,3 @@ When submitting code, please make every effort to follow existing conventions
|
|||
and style in order to keep the code as readable as possible. Please also make
|
||||
sure all tests pass by running `go test`, and format your code with `go fmt`.
|
||||
We also recommend using `golint` and `errcheck`.
|
||||
|
||||
Before your code can be accepted into the project you must also sign the
|
||||
Individual Contributor License Agreement. We use [cla-assistant.io][1] and you
|
||||
will be prompted to sign once a pull request is opened.
|
||||
|
||||
[1]: https://cla-assistant.io/
|
||||
|
|
|
@ -9,14 +9,6 @@ Package jose aims to provide an implementation of the Javascript Object Signing
|
|||
and Encryption set of standards. This includes support for JSON Web Encryption,
|
||||
JSON Web Signature, and JSON Web Token standards.
|
||||
|
||||
**Disclaimer**: This library contains encryption software that is subject to
|
||||
the U.S. Export Administration Regulations. You may not export, re-export,
|
||||
transfer or download this code or any part of it in violation of any United
|
||||
States law, directive or regulation. In particular this software may not be
|
||||
exported or re-exported in any form or on any media to Iran, North Sudan,
|
||||
Syria, Cuba, or North Korea, or to denied persons or entities mentioned on any
|
||||
US maintained blocked list.
|
||||
|
||||
## Overview
|
||||
|
||||
The implementation follows the
|
||||
|
@ -109,6 +101,6 @@ allows attaching a key id.
|
|||
|
||||
Examples can be found in the Godoc
|
||||
reference for this package. The
|
||||
[`jose-util`](https://github.com/go-jose/go-jose/tree/v4/jose-util)
|
||||
[`jose-util`](https://github.com/go-jose/go-jose/tree/main/jose-util)
|
||||
subdirectory also contains a small command-line utility which might be useful
|
||||
as an example as well.
|
||||
|
|
|
@ -288,10 +288,11 @@ func ParseEncryptedCompact(
|
|||
keyAlgorithms []KeyAlgorithm,
|
||||
contentEncryption []ContentEncryption,
|
||||
) (*JSONWebEncryption, error) {
|
||||
parts := strings.Split(input, ".")
|
||||
if len(parts) != 5 {
|
||||
// Five parts is four separators
|
||||
if strings.Count(input, ".") != 4 {
|
||||
return nil, fmt.Errorf("go-jose/go-jose: compact JWE format must have five parts")
|
||||
}
|
||||
parts := strings.SplitN(input, ".", 5)
|
||||
|
||||
rawProtected, err := base64.RawURLEncoding.DecodeString(parts[0])
|
||||
if err != nil {
|
||||
|
|
|
@ -239,10 +239,10 @@ func (k *JSONWebKey) UnmarshalJSON(data []byte) (err error) {
|
|||
keyPub = key
|
||||
}
|
||||
} else {
|
||||
err = fmt.Errorf("go-jose/go-jose: unknown curve %s'", raw.Crv)
|
||||
return fmt.Errorf("go-jose/go-jose: unknown curve %s'", raw.Crv)
|
||||
}
|
||||
default:
|
||||
err = fmt.Errorf("go-jose/go-jose: unknown json web key type '%s'", raw.Kty)
|
||||
return fmt.Errorf("go-jose/go-jose: unknown json web key type '%s'", raw.Kty)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
|
|
|
@ -327,10 +327,11 @@ func parseSignedCompact(
|
|||
payload []byte,
|
||||
signatureAlgorithms []SignatureAlgorithm,
|
||||
) (*JSONWebSignature, error) {
|
||||
parts := strings.Split(input, ".")
|
||||
if len(parts) != 3 {
|
||||
// Three parts is two separators
|
||||
if strings.Count(input, ".") != 2 {
|
||||
return nil, fmt.Errorf("go-jose/go-jose: compact JWS format must have three parts")
|
||||
}
|
||||
parts := strings.SplitN(input, ".", 3)
|
||||
|
||||
if parts[1] != "" && payload != nil {
|
||||
return nil, fmt.Errorf("go-jose/go-jose: payload is not detached")
|
||||
|
|
|
@ -99,7 +99,7 @@ github.com/containernetworking/cni/pkg/version
|
|||
# github.com/containernetworking/plugins v1.5.1
|
||||
## explicit; go 1.20
|
||||
github.com/containernetworking/plugins/pkg/ns
|
||||
# github.com/containers/common v0.62.0
|
||||
# github.com/containers/common v0.62.1
|
||||
## explicit; go 1.22.8
|
||||
github.com/containers/common/internal
|
||||
github.com/containers/common/internal/attributedstring
|
||||
|
@ -152,7 +152,7 @@ github.com/containers/common/pkg/umask
|
|||
github.com/containers/common/pkg/util
|
||||
github.com/containers/common/pkg/version
|
||||
github.com/containers/common/version
|
||||
# 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
|
||||
|
@ -369,7 +369,7 @@ github.com/fsnotify/fsnotify/internal
|
|||
# github.com/fsouza/go-dockerclient v1.12.0
|
||||
## explicit; go 1.22
|
||||
github.com/fsouza/go-dockerclient
|
||||
# github.com/go-jose/go-jose/v4 v4.0.4
|
||||
# github.com/go-jose/go-jose/v4 v4.0.5
|
||||
## explicit; go 1.21
|
||||
github.com/go-jose/go-jose/v4
|
||||
github.com/go-jose/go-jose/v4/cipher
|
||||
|
|
Loading…
Reference in New Issue