Merge pull request #17199 from ashley-cui/vendor

Vendor containers/(storage, image, common, buildah)
This commit is contained in:
OpenShift Merge Robot
2023-01-24 14:01:26 -05:00
committed by GitHub
53 changed files with 1839 additions and 696 deletions

15
go.mod
View File

@ -11,13 +11,13 @@ require (
github.com/container-orchestrated-devices/container-device-interface v0.5.3
github.com/containernetworking/cni v1.1.2
github.com/containernetworking/plugins v1.2.0
github.com/containers/buildah v1.28.1-0.20230118214707-42f2b38574c4
github.com/containers/common v0.50.2-0.20230118184424-57606d3b130f
github.com/containers/buildah v1.28.1-0.20230120225201-4b72f055f1c9
github.com/containers/common v0.51.0
github.com/containers/conmon v2.0.20+incompatible
github.com/containers/image/v5 v5.23.1-0.20230118141642-5e9b17d07ceb
github.com/containers/ocicrypt v1.1.7-0.20230115130455-e0cec6f7be0d
github.com/containers/image/v5 v5.24.0
github.com/containers/ocicrypt v1.1.7
github.com/containers/psgo v1.8.0
github.com/containers/storage v1.45.2-0.20230117181605-d5792d2dbc18
github.com/containers/storage v1.45.3
github.com/coreos/go-systemd/v22 v22.5.0
github.com/coreos/stream-metadata-go v0.0.0-20210225230131-70edb9eb47b3
github.com/cyphar/filepath-securejoin v0.2.3
@ -81,7 +81,7 @@ require (
github.com/containerd/cgroups v1.0.4 // indirect
github.com/containerd/containerd v1.6.15 // indirect
github.com/containerd/stargz-snapshotter/estargz v0.13.0 // indirect
github.com/containers/libtrust v0.0.0-20200511145503-9c3a6c22cd9a // indirect
github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01 // indirect
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f // indirect
github.com/cyberphone/json-canonicalization v0.0.0-20220623050100-57a0ce2678a7 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
@ -112,7 +112,7 @@ require (
github.com/inconshreveable/mousetrap v1.0.1 // indirect
github.com/jinzhu/copier v0.3.5 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/klauspost/compress v1.15.14 // indirect
github.com/klauspost/compress v1.15.15 // indirect
github.com/klauspost/pgzip v1.2.6-0.20220930104621-17e8dac29df8 // indirect
github.com/kr/fs v0.1.0 // indirect
github.com/letsencrypt/boulder v0.0.0-20221109233200-85aa52084eaf // indirect
@ -135,6 +135,7 @@ require (
github.com/proglottis/gpgme v0.1.3 // indirect
github.com/rivo/uniseg v0.4.3 // indirect
github.com/seccomp/libseccomp-golang v0.10.0 // indirect
github.com/sigstore/fulcio v1.0.0 // indirect
github.com/sigstore/rekor v1.0.1 // indirect
github.com/sigstore/sigstore v1.5.1 // indirect
github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980 // indirect

31
go.sum
View File

@ -265,27 +265,27 @@ github.com/containernetworking/plugins v0.8.6/go.mod h1:qnw5mN19D8fIwkqW7oHHYDHV
github.com/containernetworking/plugins v0.9.1/go.mod h1:xP/idU2ldlzN6m4p5LmGiwRDjeJr6FLK6vuiUwoH7P8=
github.com/containernetworking/plugins v1.2.0 h1:SWgg3dQG1yzUo4d9iD8cwSVh1VqI+bP7mkPDoSfP9VU=
github.com/containernetworking/plugins v1.2.0/go.mod h1:/VjX4uHecW5vVimFa1wkG4s+r/s9qIfPdqlLF4TW8c4=
github.com/containers/buildah v1.28.1-0.20230118214707-42f2b38574c4 h1:bp6DcKOlaAWdRJSoDQ6XQLfMZWddxQYWEpZAnwt+CPg=
github.com/containers/buildah v1.28.1-0.20230118214707-42f2b38574c4/go.mod h1:BVAeQ0Hsctmze9fLimjaQDg9QPa/Lbtr61LB7dPNdRg=
github.com/containers/common v0.50.2-0.20230118184424-57606d3b130f h1:X9DbI8ImXry6FgERXY/rcVpZrKAXheYG9riF8JOMDNI=
github.com/containers/common v0.50.2-0.20230118184424-57606d3b130f/go.mod h1:b9j+X2HJ0/H/lW5GJ6GqxegVmk8B6I9JgctaFLapuH8=
github.com/containers/buildah v1.28.1-0.20230120225201-4b72f055f1c9 h1:PYCbWPONH1wayhsex2lOzPHNNkJsb0/JLJbqsvVwiok=
github.com/containers/buildah v1.28.1-0.20230120225201-4b72f055f1c9/go.mod h1:jn51X0ofkH9qWsNnAv9ykPC49SyKXMhX1zJ6EDrkGII=
github.com/containers/common v0.51.0 h1:Ax4YHNTG8cEPHZJcMYRoP7sfBgOISceeyOvmZzmSucg=
github.com/containers/common v0.51.0/go.mod h1:3W2WIdalgQfrsX/T5tjX+6CxgT3ThJVN2G9sNuFjuCM=
github.com/containers/conmon v2.0.20+incompatible h1:YbCVSFSCqFjjVwHTPINGdMX1F6JXHGTUje2ZYobNrkg=
github.com/containers/conmon v2.0.20+incompatible/go.mod h1:hgwZ2mtuDrppv78a/cOBNiCm6O0UMWGx1mu7P00nu5I=
github.com/containers/image/v5 v5.23.1-0.20230118141642-5e9b17d07ceb h1:Lssw1hwohSnGLo7Md8mCTA03pXF2yD9BVSaZY/5/Y0M=
github.com/containers/image/v5 v5.23.1-0.20230118141642-5e9b17d07ceb/go.mod h1:o8iuxG+fHh3lRszzXGFMN5ANYxpgbTzL0eDUMloHCoQ=
github.com/containers/libtrust v0.0.0-20200511145503-9c3a6c22cd9a h1:spAGlqziZjCJL25C6F1zsQY05tfCKE9F5YwtEWWe6hU=
github.com/containers/libtrust v0.0.0-20200511145503-9c3a6c22cd9a/go.mod h1:9rfv8iPl1ZP7aqh9YA68wnZv2NUDbXdcdPHVz0pFbPY=
github.com/containers/image/v5 v5.24.0 h1:2Pu8ztTntqNxteVN15bORCQnM8rfnbYuyKwUiiKUBuc=
github.com/containers/image/v5 v5.24.0/go.mod h1:oss5F6ssGQz8ZtC79oY+fuzYA3m3zBek9tq9gmhuvHc=
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.0.1/go.mod h1:MeJDzk1RJHv89LjsH0Sp5KTY3ZYkjXO/C+bKAeWFIrc=
github.com/containers/ocicrypt v1.1.0/go.mod h1:b8AOe0YR67uU8OqfVNcznfFpAzu3rdgUV4GP9qXPfu4=
github.com/containers/ocicrypt v1.1.1/go.mod h1:Dm55fwWm1YZAjYRaJ94z2mfZikIyIN4B0oB3dj3jFxY=
github.com/containers/ocicrypt v1.1.7-0.20230115130455-e0cec6f7be0d h1:9PyNGtThqLWgN0JnczaWEPEYfrLhITsSzwljJNurfwE=
github.com/containers/ocicrypt v1.1.7-0.20230115130455-e0cec6f7be0d/go.mod h1:k6j0C2yEGkwl+mOhD1pJ54H7RaDRkLKmucMSZfVrIzA=
github.com/containers/ocicrypt v1.1.7 h1:thhNr4fu2ltyGz8aMx8u48Ae0Pnbip3ePP9/mzkZ/3U=
github.com/containers/ocicrypt v1.1.7/go.mod h1:7CAhjcj2H8AYp5YvEie7oVSK2AhBY8NscCYRawuDNtw=
github.com/containers/psgo v1.8.0 h1:2loGekmGAxM9ir5OsXWEfGwFxorMPYnc6gEDsGFQvhY=
github.com/containers/psgo v1.8.0/go.mod h1:T8ZxnX3Ur4RvnhxFJ7t8xJ1F48RhiZB4rSrOaR/qGHc=
github.com/containers/storage v1.37.0/go.mod h1:kqeJeS0b7DO2ZT1nVWs0XufrmPFbgV3c+Q/45RlH6r4=
github.com/containers/storage v1.43.0/go.mod h1:uZ147thiIFGdVTjMmIw19knttQnUCl3y9zjreHrg11s=
github.com/containers/storage v1.45.2-0.20230117181605-d5792d2dbc18 h1:u/gpJJHQrbbU2jEof7LSL6zFgXTTK5oCYEgFce6NVTw=
github.com/containers/storage v1.45.2-0.20230117181605-d5792d2dbc18/go.mod h1:OdRUYHrq1HP6iAo79VxqtYuJzC5j4eA2I60jKOoCT7g=
github.com/containers/storage v1.45.3 h1:GbtTvTtp3GW2/tcFg5VhgHXcYMwVn2KfZKiHjf9FAOM=
github.com/containers/storage v1.45.3/go.mod h1:OdRUYHrq1HP6iAo79VxqtYuJzC5j4eA2I60jKOoCT7g=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-iptables v0.4.5/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU=
@ -362,7 +362,6 @@ github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDD
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE=
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 h1:UhxFibDNY/bfvqU5CAUmr9zpesgbU6SWc8/B4mflAE4=
github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
@ -685,8 +684,8 @@ github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47e
github.com/klauspost/compress v1.15.7/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
github.com/klauspost/compress v1.15.12/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM=
github.com/klauspost/compress v1.15.14 h1:i7WCKDToww0wA+9qrUZ1xOjp218vfFo3nTU6UHp+gOc=
github.com/klauspost/compress v1.15.14/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM=
github.com/klauspost/compress v1.15.15 h1:EF27CXIuDsYJ6mmvtBRlEuB2UVOqHG1tAXgZ7yIO+lw=
github.com/klauspost/compress v1.15.15/go.mod h1:ZcK2JAFqKOpnBlxcLsJzYfrS9X1akm9fHZNnD9+Vo/4=
github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
github.com/klauspost/pgzip v1.2.6-0.20220930104621-17e8dac29df8 h1:BcxbplxjtczA1a6d3wYoa7a0WL3rq9DKBMGHeKyjEF0=
github.com/klauspost/pgzip v1.2.6-0.20220930104621-17e8dac29df8/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
@ -936,6 +935,8 @@ github.com/seccomp/libseccomp-golang v0.10.0 h1:aA4bp+/Zzi0BnWZ2F1wgNBs5gTpm+na2
github.com/seccomp/libseccomp-golang v0.10.0/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg=
github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sigstore/fulcio v1.0.0 h1:hBZW6qg9GXTtCX8jOg1hmyjYLrmsEKZGeMwAbW3XNEg=
github.com/sigstore/fulcio v1.0.0/go.mod h1:j4MzLxX/Be0rHYh3JF2dgMorkWGzEMHBqIHwFU8I/Rw=
github.com/sigstore/rekor v1.0.1 h1:rcESXSNkAPRWFYZel9rarspdvneET60F2ngNkadi89c=
github.com/sigstore/rekor v1.0.1/go.mod h1:ecTKdZWGWqE1pl3U1m1JebQJLU/hSjD9vYHOmHQ7w4g=
github.com/sigstore/sigstore v1.5.1 h1:iUou0QJW8eQKMUkTXbFyof9ZOblDtfaW2Sn2+QI8Tcs=

View File

@ -1,4 +1,4 @@
package version
// Version is the version of the build.
const Version = "0.50.2-dev"
const Version = "0.51.0"

View File

@ -0,0 +1,174 @@
package signature
import (
"crypto"
"crypto/ecdsa"
"crypto/x509"
"encoding/asn1"
"errors"
"fmt"
"time"
"github.com/containers/image/v5/signature/internal"
"github.com/sigstore/fulcio/pkg/certificate"
"github.com/sigstore/sigstore/pkg/cryptoutils"
)
// fulcioTrustRoot contains policy allow validating Fulcio-issued certificates.
// Users should call validate() on the policy before using it.
type fulcioTrustRoot struct {
caCertificates *x509.CertPool
oidcIssuer string
subjectEmail string
}
func (f *fulcioTrustRoot) validate() error {
if f.oidcIssuer == "" {
return errors.New("Internal inconsistency: Fulcio use set up without OIDC issuer")
}
if f.subjectEmail == "" {
return errors.New("Internal inconsistency: Fulcio use set up without subject email")
}
return nil
}
func (f *fulcioTrustRoot) verifyFulcioCertificateAtTime(relevantTime time.Time, untrustedCertificateBytes []byte, untrustedIntermediateChainBytes []byte) (crypto.PublicKey, error) {
// == Verify the certificate is correctly signed
var untrustedIntermediatePool *x509.CertPool // = nil
// untrustedCertificateChainPool.AppendCertsFromPEM does something broadly similar,
// but it seems to optimize for memory usage at the cost of larger CPU usage (i.e. to load
// the hundreds of trusted CAs). Golangs TLS code similarly calls individual AddCert
// for intermediate certificates.
if len(untrustedIntermediateChainBytes) > 0 {
untrustedIntermediateChain, err := cryptoutils.UnmarshalCertificatesFromPEM(untrustedIntermediateChainBytes)
if err != nil {
return nil, internal.NewInvalidSignatureError(fmt.Sprintf("loading certificate chain: %v", err))
}
untrustedIntermediatePool = x509.NewCertPool()
if len(untrustedIntermediateChain) > 1 {
for _, untrustedIntermediateCert := range untrustedIntermediateChain[:len(untrustedIntermediateChain)-1] {
untrustedIntermediatePool.AddCert(untrustedIntermediateCert)
}
}
}
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:
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.
if len(untrustedCertificate.UnhandledCriticalExtensions) > 0 {
var remaining []asn1.ObjectIdentifier
for _, oid := range untrustedCertificate.UnhandledCriticalExtensions {
if !oid.Equal(cryptoutils.SANOID) {
remaining = append(remaining, oid)
}
}
untrustedCertificate.UnhandledCriticalExtensions = remaining
}
if _, err := untrustedCertificate.Verify(x509.VerifyOptions{
Intermediates: untrustedIntermediatePool,
Roots: f.caCertificates,
// NOTE: Cosign uses untrustedCertificate.NotBefore here (i.e. uses _that_ time for intermediate certificate validation),
// and validates the leaf certificate against relevantTime manually.
// We verify the full certificate chain against relevantTime instead.
// Assuming the certificate is fulcio-generated and very short-lived, that should make little difference.
CurrentTime: relevantTime,
KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageCodeSigning},
}); err != nil {
return nil, internal.NewInvalidSignatureError(fmt.Sprintf("veryfing leaf certificate failed: %v", err))
}
// Cosign verifies a SCT of the certificate (either embedded, or even, probably irrelevant, externally-supplied).
//
// We dont currently do that.
//
// At the very least, with Fulcio we require Rekor SETs to prove Rekor contains a log of the signature, and that
// already contains the full certificate; so a SCT of the certificate is superfluous (assuming Rekor allowed searching by
// certificate subject, which, well…). That argument might go away if we add support for RFC 3161 timestamps instead of Rekor.
//
// Secondarily, assuming a trusted Fulcio server (which, to be fair, might not be the case for the public one) SCT is not clearly
// better than the Fulcio server maintaining an audit log; a SCT can only reveal a misissuance if there is some other authoritative
// log of approved Fulcio invocations, and its not clear where that would come from, especially human users manually
// logging in using OpenID are not going to maintain a record of those actions.
//
// Also, the SCT does not help reveal _what_ was maliciously signed, nor does it protect against malicous signatures
// by correctly-issued certificates.
//
// So, pragmatically, the ideal design seem to be to only do signatures from a trusted build system (which is, by definition,
// the arbiter of desired vs. malicious signatures) that maintains an audit log of performed signature operations; and that seems to
// make make the SCT (and all of Rekor apart from the trusted timestamp) unnecessary.
// == Validate the recorded OIDC issuer
gotOIDCIssuer := false
var oidcIssuer string
// certificate.ParseExtensions doesnt reject duplicate extensions.
// Go 1.19 rejects duplicate extensions universally; but until we can require Go 1.19,
// reject duplicates manually. With Go 1.19, we could call certificate.ParseExtensions again.
for _, untrustedExt := range untrustedCertificate.Extensions {
if untrustedExt.Id.Equal(certificate.OIDIssuer) {
if gotOIDCIssuer {
// Coverage: This is unreachable in Go ≥1.19, which rejects certificates with duplicate extensions
// already in ParseCertificate.
return nil, internal.NewInvalidSignatureError("Fulcio certificate has a duplicate OIDC issuer extension")
}
oidcIssuer = string(untrustedExt.Value)
gotOIDCIssuer = true
}
}
if !gotOIDCIssuer {
return nil, internal.NewInvalidSignatureError("Fulcio certificate is missing the issuer extension")
}
if oidcIssuer != f.oidcIssuer {
return nil, internal.NewInvalidSignatureError(fmt.Sprintf("Unexpected Fulcio OIDC issuer %q", oidcIssuer))
}
// == Validate the OIDC subject
foundEmail := false
// TO DO: Use slices.Contains after we update to Go 1.18
for _, certEmail := range untrustedCertificate.EmailAddresses {
if certEmail == f.subjectEmail {
foundEmail = true
break
}
}
if !foundEmail {
return nil, internal.NewInvalidSignatureError(fmt.Sprintf("Required email %s not found (got %#v)",
f.subjectEmail,
untrustedCertificate.EmailAddresses))
}
// FIXME: Match more subject types? Cosign does:
// - .DNSNames (cant be issued by Fulcio)
// - .IPAddresses (cant be issued by Fulcio)
// - .URIs (CAN be issued by Fulcio)
// - OtherName values in SAN (CAN be issued by Fulcio)
// - Various values about GitHub workflows (CAN be issued by Fulcio)
// What does it… mean to get an OAuth2 identity for an IP address?
// FIXME: How far into Turing-completeness for the issuer/subject do we need to get? Simultaneously accepted alternatives, for
// issuers and/or subjects and/or combinations? Regexps? More?
return untrustedCertificate.PublicKey, nil
}
func verifyRekorFulcio(rekorPublicKey *ecdsa.PublicKey, fulcioTrustRoot *fulcioTrustRoot, untrustedRekorSET []byte,
untrustedCertificateBytes []byte, untrustedIntermediateChainBytes []byte, untrustedBase64Signature string,
untrustedPayloadBytes []byte) (crypto.PublicKey, error) {
rekorSETTime, err := internal.VerifyRekorSET(rekorPublicKey, untrustedRekorSET, untrustedCertificateBytes,
untrustedBase64Signature, untrustedPayloadBytes)
if err != nil {
return nil, err
}
return fulcioTrustRoot.verifyFulcioCertificateAtTime(rekorSETTime, untrustedCertificateBytes, untrustedIntermediateChainBytes)
}

View File

@ -518,107 +518,6 @@ func (pr *prSignedBaseLayer) UnmarshalJSON(data []byte) error {
return nil
}
// newPRSigstoreSigned returns a new prSigstoreSigned if parameters are valid.
func newPRSigstoreSigned(keyPath string, keyData []byte, signedIdentity PolicyReferenceMatch) (*prSigstoreSigned, error) {
if len(keyPath) > 0 && len(keyData) > 0 {
return nil, InvalidPolicyFormatError("keyType and keyData cannot be used simultaneously")
}
if signedIdentity == nil {
return nil, InvalidPolicyFormatError("signedIdentity not specified")
}
return &prSigstoreSigned{
prCommon: prCommon{Type: prTypeSigstoreSigned},
KeyPath: keyPath,
KeyData: keyData,
SignedIdentity: signedIdentity,
}, nil
}
// newPRSigstoreSignedKeyPath is NewPRSigstoreSignedKeyPath, except it returns the private type.
func newPRSigstoreSignedKeyPath(keyPath string, signedIdentity PolicyReferenceMatch) (*prSigstoreSigned, error) {
return newPRSigstoreSigned(keyPath, nil, signedIdentity)
}
// NewPRSigstoreSignedKeyPath returns a new "sigstoreSigned" PolicyRequirement using a KeyPath
func NewPRSigstoreSignedKeyPath(keyPath string, signedIdentity PolicyReferenceMatch) (PolicyRequirement, error) {
return newPRSigstoreSignedKeyPath(keyPath, signedIdentity)
}
// newPRSigstoreSignedKeyData is NewPRSigstoreSignedKeyData, except it returns the private type.
func newPRSigstoreSignedKeyData(keyData []byte, signedIdentity PolicyReferenceMatch) (*prSigstoreSigned, error) {
return newPRSigstoreSigned("", keyData, signedIdentity)
}
// NewPRSigstoreSignedKeyData returns a new "sigstoreSigned" PolicyRequirement using a KeyData
func NewPRSigstoreSignedKeyData(keyData []byte, signedIdentity PolicyReferenceMatch) (PolicyRequirement, error) {
return newPRSigstoreSignedKeyData(keyData, signedIdentity)
}
// Compile-time check that prSigstoreSigned implements json.Unmarshaler.
var _ json.Unmarshaler = (*prSigstoreSigned)(nil)
// UnmarshalJSON implements the json.Unmarshaler interface.
func (pr *prSigstoreSigned) UnmarshalJSON(data []byte) error {
*pr = prSigstoreSigned{}
var tmp prSigstoreSigned
var gotKeyPath, gotKeyData = false, false
var signedIdentity json.RawMessage
if err := internal.ParanoidUnmarshalJSONObject(data, func(key string) interface{} {
switch key {
case "type":
return &tmp.Type
case "keyPath":
gotKeyPath = true
return &tmp.KeyPath
case "keyData":
gotKeyData = true
return &tmp.KeyData
case "signedIdentity":
return &signedIdentity
default:
return nil
}
}); err != nil {
return err
}
if tmp.Type != prTypeSigstoreSigned {
return InvalidPolicyFormatError(fmt.Sprintf("Unexpected policy requirement type \"%s\"", tmp.Type))
}
if signedIdentity == nil {
tmp.SignedIdentity = NewPRMMatchRepoDigestOrExact()
} else {
si, err := newPolicyReferenceMatchFromJSON(signedIdentity)
if err != nil {
return err
}
tmp.SignedIdentity = si
}
var res *prSigstoreSigned
var err error
switch {
case gotKeyPath && gotKeyData:
return InvalidPolicyFormatError("keyPath and keyData cannot be used simultaneously")
case gotKeyPath && !gotKeyData:
res, err = newPRSigstoreSignedKeyPath(tmp.KeyPath, tmp.SignedIdentity)
case !gotKeyPath && gotKeyData:
res, err = newPRSigstoreSignedKeyData(tmp.KeyData, tmp.SignedIdentity)
case !gotKeyPath && !gotKeyData:
return InvalidPolicyFormatError("At least one of keyPath and keyData must be specified")
default: // Coverage: This should never happen
return fmt.Errorf("Impossible keyPath/keyData presence combination!?")
}
if err != nil {
// Coverage: This cannot currently happen, creating a prSigstoreSigned only fails
// if signedIdentity is nil, which we replace with a default above.
return err
}
*pr = *res
return nil
}
// newPolicyReferenceMatchFromJSON parses JSON data into a PolicyReferenceMatch implementation.
func newPolicyReferenceMatchFromJSON(data []byte) (PolicyReferenceMatch, error) {
var typeField prmCommon

View File

@ -0,0 +1,343 @@
package signature
import (
"encoding/json"
"errors"
"fmt"
"github.com/containers/image/v5/signature/internal"
)
// PRSigstoreSignedOption is way to pass values to NewPRSigstoreSigned
type PRSigstoreSignedOption func(*prSigstoreSigned) error
// PRSigstoreSignedWithKeyPath specifies a value for the "keyPath" field when calling NewPRSigstoreSigned.
func PRSigstoreSignedWithKeyPath(keyPath string) PRSigstoreSignedOption {
return func(pr *prSigstoreSigned) error {
if pr.KeyPath != "" {
return errors.New(`"keyPath" already specified`)
}
pr.KeyPath = keyPath
return nil
}
}
// PRSigstoreSignedWithKeyData specifies a value for the "keyData" field when calling NewPRSigstoreSigned.
func PRSigstoreSignedWithKeyData(keyData []byte) PRSigstoreSignedOption {
return func(pr *prSigstoreSigned) error {
if pr.KeyData != nil {
return errors.New(`"keyData" already specified`)
}
pr.KeyData = keyData
return nil
}
}
// PRSigstoreSignedWithFulcio specifies a value for the "fulcio" field when calling NewPRSigstoreSigned.
func PRSigstoreSignedWithFulcio(fulcio PRSigstoreSignedFulcio) PRSigstoreSignedOption {
return func(pr *prSigstoreSigned) error {
if pr.Fulcio != nil {
return errors.New(`"fulcio" already specified`)
}
pr.Fulcio = fulcio
return nil
}
}
// PRSigstoreSignedWithRekorPublicKeyPath specifies a value for the "rekorPublicKeyPath" field when calling NewPRSigstoreSigned.
func PRSigstoreSignedWithRekorPublicKeyPath(rekorPublicKeyPath string) PRSigstoreSignedOption {
return func(pr *prSigstoreSigned) error {
if pr.RekorPublicKeyPath != "" {
return errors.New(`"rekorPublicKeyPath" already specified`)
}
pr.RekorPublicKeyPath = rekorPublicKeyPath
return nil
}
}
// PRSigstoreSignedWithRekorPublicKeyData specifies a value for the "rekorPublicKeyData" field when calling NewPRSigstoreSigned.
func PRSigstoreSignedWithRekorPublicKeyData(rekorPublicKeyData []byte) PRSigstoreSignedOption {
return func(pr *prSigstoreSigned) error {
if pr.RekorPublicKeyData != nil {
return errors.New(`"rekorPublicKeyData" already specified`)
}
pr.RekorPublicKeyData = rekorPublicKeyData
return nil
}
}
// PRSigstoreSignedWithSignedIdentity specifies a value for the "signedIdentity" field when calling NewPRSigstoreSigned.
func PRSigstoreSignedWithSignedIdentity(signedIdentity PolicyReferenceMatch) PRSigstoreSignedOption {
return func(pr *prSigstoreSigned) error {
if pr.SignedIdentity != nil {
return errors.New(`"signedIdentity" already specified`)
}
pr.SignedIdentity = signedIdentity
return nil
}
}
// newPRSigstoreSigned is NewPRSigstoreSigned, except it returns the private type.
func newPRSigstoreSigned(options ...PRSigstoreSignedOption) (*prSigstoreSigned, error) {
res := prSigstoreSigned{
prCommon: prCommon{Type: prTypeSigstoreSigned},
}
for _, o := range options {
if err := o(&res); err != nil {
return nil, err
}
}
keySources := 0
if res.KeyPath != "" {
keySources++
}
if res.KeyData != nil {
keySources++
}
if res.Fulcio != nil {
keySources++
}
if keySources != 1 {
return nil, InvalidPolicyFormatError("exactly one of keyPath, keyData and fulcio must be specified")
}
if res.RekorPublicKeyPath != "" && res.RekorPublicKeyData != nil {
return nil, InvalidPolicyFormatError("rekorPublickeyType and rekorPublickeyData cannot be used simultaneously")
}
if res.Fulcio != nil && res.RekorPublicKeyPath == "" && res.RekorPublicKeyData == nil {
return nil, InvalidPolicyFormatError("At least one of RekorPublickeyPath and RekorPublickeyData must be specified if fulcio is used")
}
if res.SignedIdentity == nil {
return nil, InvalidPolicyFormatError("signedIdentity not specified")
}
return &res, nil
}
// NewPRSigstoreSigned returns a new "sigstoreSigned" PolicyRequirement based on options.
func NewPRSigstoreSigned(options ...PRSigstoreSignedOption) (PolicyRequirement, error) {
return newPRSigstoreSigned(options...)
}
// NewPRSigstoreSignedKeyPath returns a new "sigstoreSigned" PolicyRequirement using a KeyPath
func NewPRSigstoreSignedKeyPath(keyPath string, signedIdentity PolicyReferenceMatch) (PolicyRequirement, error) {
return NewPRSigstoreSigned(
PRSigstoreSignedWithKeyPath(keyPath),
PRSigstoreSignedWithSignedIdentity(signedIdentity),
)
}
// NewPRSigstoreSignedKeyData returns a new "sigstoreSigned" PolicyRequirement using a KeyData
func NewPRSigstoreSignedKeyData(keyData []byte, signedIdentity PolicyReferenceMatch) (PolicyRequirement, error) {
return NewPRSigstoreSigned(
PRSigstoreSignedWithKeyData(keyData),
PRSigstoreSignedWithSignedIdentity(signedIdentity),
)
}
// Compile-time check that prSigstoreSigned implements json.Unmarshaler.
var _ json.Unmarshaler = (*prSigstoreSigned)(nil)
// UnmarshalJSON implements the json.Unmarshaler interface.
func (pr *prSigstoreSigned) UnmarshalJSON(data []byte) error {
*pr = prSigstoreSigned{}
var tmp prSigstoreSigned
var gotKeyPath, gotKeyData, gotFulcio, gotRekorPublicKeyPath, gotRekorPublicKeyData bool
var fulcio prSigstoreSignedFulcio
var signedIdentity json.RawMessage
if err := internal.ParanoidUnmarshalJSONObject(data, func(key string) interface{} {
switch key {
case "type":
return &tmp.Type
case "keyPath":
gotKeyPath = true
return &tmp.KeyPath
case "keyData":
gotKeyData = true
return &tmp.KeyData
case "fulcio":
gotFulcio = true
return &fulcio
case "rekorPublicKeyPath":
gotRekorPublicKeyPath = true
return &tmp.RekorPublicKeyPath
case "rekorPublicKeyData":
gotRekorPublicKeyData = true
return &tmp.RekorPublicKeyData
case "signedIdentity":
return &signedIdentity
default:
return nil
}
}); err != nil {
return err
}
if tmp.Type != prTypeSigstoreSigned {
return InvalidPolicyFormatError(fmt.Sprintf("Unexpected policy requirement type \"%s\"", tmp.Type))
}
if signedIdentity == nil {
tmp.SignedIdentity = NewPRMMatchRepoDigestOrExact()
} else {
si, err := newPolicyReferenceMatchFromJSON(signedIdentity)
if err != nil {
return err
}
tmp.SignedIdentity = si
}
var opts []PRSigstoreSignedOption
if gotKeyPath {
opts = append(opts, PRSigstoreSignedWithKeyPath(tmp.KeyPath))
}
if gotKeyData {
opts = append(opts, PRSigstoreSignedWithKeyData(tmp.KeyData))
}
if gotFulcio {
opts = append(opts, PRSigstoreSignedWithFulcio(&fulcio))
}
if gotRekorPublicKeyPath {
opts = append(opts, PRSigstoreSignedWithRekorPublicKeyPath(tmp.RekorPublicKeyPath))
}
if gotRekorPublicKeyData {
opts = append(opts, PRSigstoreSignedWithRekorPublicKeyData(tmp.RekorPublicKeyData))
}
opts = append(opts, PRSigstoreSignedWithSignedIdentity(tmp.SignedIdentity))
res, err := newPRSigstoreSigned(opts...)
if err != nil {
return err
}
*pr = *res
return nil
}
// PRSigstoreSignedFulcioOption is a way to pass values to NewPRSigstoreSignedFulcio
type PRSigstoreSignedFulcioOption func(*prSigstoreSignedFulcio) error
// PRSigstoreSignedFulcioWithCAPath specifies a value for the "caPath" field when calling NewPRSigstoreSignedFulcio
func PRSigstoreSignedFulcioWithCAPath(caPath string) PRSigstoreSignedFulcioOption {
return func(f *prSigstoreSignedFulcio) error {
if f.CAPath != "" {
return errors.New(`"caPath" already specified`)
}
f.CAPath = caPath
return nil
}
}
// PRSigstoreSignedFulcioWithCAData specifies a value for the "caData" field when calling NewPRSigstoreSignedFulcio
func PRSigstoreSignedFulcioWithCAData(caData []byte) PRSigstoreSignedFulcioOption {
return func(f *prSigstoreSignedFulcio) error {
if f.CAData != nil {
return errors.New(`"caData" already specified`)
}
f.CAData = caData
return nil
}
}
// PRSigstoreSignedFulcioWithOIDCIssuer specifies a value for the "oidcIssuer" field when calling NewPRSigstoreSignedFulcio
func PRSigstoreSignedFulcioWithOIDCIssuer(oidcIssuer string) PRSigstoreSignedFulcioOption {
return func(f *prSigstoreSignedFulcio) error {
if f.OIDCIssuer != "" {
return errors.New(`"oidcIssuer" already specified`)
}
f.OIDCIssuer = oidcIssuer
return nil
}
}
// PRSigstoreSignedFulcioWithSubjectEmail specifies a value for the "subjectEmail" field when calling NewPRSigstoreSignedFulcio
func PRSigstoreSignedFulcioWithSubjectEmail(subjectEmail string) PRSigstoreSignedFulcioOption {
return func(f *prSigstoreSignedFulcio) error {
if f.SubjectEmail != "" {
return errors.New(`"subjectEmail" already specified`)
}
f.SubjectEmail = subjectEmail
return nil
}
}
// newPRSigstoreSignedFulcio is NewPRSigstoreSignedFulcio, except it returns the private type
func newPRSigstoreSignedFulcio(options ...PRSigstoreSignedFulcioOption) (*prSigstoreSignedFulcio, error) {
res := prSigstoreSignedFulcio{}
for _, o := range options {
if err := o(&res); err != nil {
return nil, err
}
}
if res.CAPath != "" && res.CAData != nil {
return nil, InvalidPolicyFormatError("caPath and caData cannot be used simultaneously")
}
if res.CAPath == "" && res.CAData == nil {
return nil, InvalidPolicyFormatError("At least one of caPath and caData must be specified")
}
if res.OIDCIssuer == "" {
return nil, InvalidPolicyFormatError("oidcIssuer not specified")
}
if res.SubjectEmail == "" {
return nil, InvalidPolicyFormatError("subjectEmail not specified")
}
return &res, nil
}
// NewPRSigstoreSignedFulcio returns a PRSigstoreSignedFulcio based on options.
func NewPRSigstoreSignedFulcio(options ...PRSigstoreSignedFulcioOption) (PRSigstoreSignedFulcio, error) {
return newPRSigstoreSignedFulcio(options...)
}
// Compile-time check that prSigstoreSignedFulcio implements json.Unmarshaler.
var _ json.Unmarshaler = (*prSigstoreSignedFulcio)(nil)
func (f *prSigstoreSignedFulcio) UnmarshalJSON(data []byte) error {
*f = prSigstoreSignedFulcio{}
var tmp prSigstoreSignedFulcio
var gotCAPath, gotCAData, gotOIDCIssuer, gotSubjectEmail bool // = false...
if err := internal.ParanoidUnmarshalJSONObject(data, func(key string) interface{} {
switch key {
case "caPath":
gotCAPath = true
return &tmp.CAPath
case "caData":
gotCAData = true
return &tmp.CAData
case "oidcIssuer":
gotOIDCIssuer = true
return &tmp.OIDCIssuer
case "subjectEmail":
gotSubjectEmail = true
return &tmp.SubjectEmail
default:
return nil
}
}); err != nil {
return err
}
var opts []PRSigstoreSignedFulcioOption
if gotCAPath {
opts = append(opts, PRSigstoreSignedFulcioWithCAPath(tmp.CAPath))
}
if gotCAData {
opts = append(opts, PRSigstoreSignedFulcioWithCAData(tmp.CAData))
}
if gotOIDCIssuer {
opts = append(opts, PRSigstoreSignedFulcioWithOIDCIssuer(tmp.OIDCIssuer))
}
if gotSubjectEmail {
opts = append(opts, PRSigstoreSignedFulcioWithSubjectEmail(tmp.SubjectEmail))
}
res, err := newPRSigstoreSignedFulcio(opts...)
if err != nil {
return err
}
*f = *res
return nil
}

View File

@ -4,6 +4,9 @@ package signature
import (
"context"
"crypto"
"crypto/ecdsa"
"crypto/x509"
"errors"
"fmt"
"os"
@ -17,6 +20,100 @@ import (
"github.com/sigstore/sigstore/pkg/cryptoutils"
)
// loadBytesFromDataOrPath ensures there is at most one of ${prefix}Data and ${prefix}Path set,
// and returns the referenced data, or nil if neither is set.
func loadBytesFromDataOrPath(prefix string, data []byte, path string) ([]byte, error) {
switch {
case data != nil && path != "":
return nil, fmt.Errorf(`Internal inconsistency: both "%sPath" and "%sData" specified`, prefix, prefix)
case path != "":
d, err := os.ReadFile(path)
if err != nil {
return nil, err
}
return d, nil
case data != nil:
return data, nil
default: // Nothing
return nil, nil
}
}
// prepareTrustRoot creates a fulcioTrustRoot from the input data.
// (This also prevents external implementations of this interface, ensuring that prSigstoreSignedFulcio is the only one.)
func (f *prSigstoreSignedFulcio) prepareTrustRoot() (*fulcioTrustRoot, error) {
caCertBytes, err := loadBytesFromDataOrPath("fulcioCA", f.CAData, f.CAPath)
if err != nil {
return nil, err
}
if caCertBytes == nil {
return nil, errors.New(`Internal inconsistency: Fulcio specified with neither "caPath" nor "caData"`)
}
certs := x509.NewCertPool()
if ok := certs.AppendCertsFromPEM(caCertBytes); !ok {
return nil, errors.New("error loading Fulcio CA certificates")
}
fulcio := fulcioTrustRoot{
caCertificates: certs,
oidcIssuer: f.OIDCIssuer,
subjectEmail: f.SubjectEmail,
}
if err := fulcio.validate(); err != nil {
return nil, err
}
return &fulcio, nil
}
// sigstoreSignedTrustRoot contains an already parsed version of the prSigstoreSigned policy
type sigstoreSignedTrustRoot struct {
publicKey crypto.PublicKey
fulcio *fulcioTrustRoot
rekorPublicKey *ecdsa.PublicKey
}
func (pr *prSigstoreSigned) prepareTrustRoot() (*sigstoreSignedTrustRoot, error) {
res := sigstoreSignedTrustRoot{}
publicKeyPEM, err := loadBytesFromDataOrPath("key", pr.KeyData, pr.KeyPath)
if err != nil {
return nil, err
}
if publicKeyPEM != nil {
pk, err := cryptoutils.UnmarshalPEMToPublicKey(publicKeyPEM)
if err != nil {
return nil, fmt.Errorf("parsing public key: %w", err)
}
res.publicKey = pk
}
if pr.Fulcio != nil {
f, err := pr.Fulcio.prepareTrustRoot()
if err != nil {
return nil, err
}
res.fulcio = f
}
rekorPublicKeyPEM, err := loadBytesFromDataOrPath("rekorPublicKey", pr.RekorPublicKeyData, pr.RekorPublicKeyPath)
if err != nil {
return nil, err
}
if rekorPublicKeyPEM != nil {
pk, err := cryptoutils.UnmarshalPEMToPublicKey(rekorPublicKeyPEM)
if err != nil {
return nil, fmt.Errorf("parsing Rekor public key: %w", err)
}
pkECDSA, ok := pk.(*ecdsa.PublicKey)
if !ok {
return nil, fmt.Errorf("Rekor public key is not using ECDSA")
}
res.rekorPublicKey = pkECDSA
}
return &res, nil
}
func (pr *prSigstoreSigned) isSignatureAuthorAccepted(ctx context.Context, image private.UnparsedImage, sig []byte) (signatureAcceptanceResult, *Signature, error) {
// We dont know of a single user of this API, and we might return unexpected values in Signature.
// For now, just punt.
@ -24,24 +121,10 @@ func (pr *prSigstoreSigned) isSignatureAuthorAccepted(ctx context.Context, image
}
func (pr *prSigstoreSigned) isSignatureAccepted(ctx context.Context, image private.UnparsedImage, sig signature.Sigstore) (signatureAcceptanceResult, error) {
if pr.KeyPath != "" && pr.KeyData != nil {
return sarRejected, errors.New(`Internal inconsistency: both "keyPath" and "keyData" specified`)
}
// FIXME: move this to per-context initialization
var publicKeyPEM []byte
if pr.KeyData != nil {
publicKeyPEM = pr.KeyData
} else {
d, err := os.ReadFile(pr.KeyPath)
if err != nil {
return sarRejected, err
}
publicKeyPEM = d
}
publicKey, err := cryptoutils.UnmarshalPEMToPublicKey(publicKeyPEM)
trustRoot, err := pr.prepareTrustRoot()
if err != nil {
return sarRejected, fmt.Errorf("parsing public key: %w", err)
return sarRejected, err
}
untrustedAnnotations := sig.UntrustedAnnotations()
@ -49,8 +132,66 @@ func (pr *prSigstoreSigned) isSignatureAccepted(ctx context.Context, image priva
if !ok {
return sarRejected, fmt.Errorf("missing %s annotation", signature.SigstoreSignatureAnnotationKey)
}
untrustedPayload := sig.UntrustedPayload()
signature, err := internal.VerifySigstorePayload(publicKey, sig.UntrustedPayload(), untrustedBase64Signature, internal.SigstorePayloadAcceptanceRules{
var publicKey crypto.PublicKey
switch {
case trustRoot.publicKey != nil && trustRoot.fulcio != nil: // newPRSigstoreSigned rejects such combinations.
return sarRejected, errors.New("Internal inconsistency: Both a public key and Fulcio CA specified")
case trustRoot.publicKey == nil && trustRoot.fulcio == nil: // newPRSigstoreSigned rejects such combinations.
return sarRejected, errors.New("Internal inconsistency: Neither a public key nor a Fulcio CA specified")
case trustRoot.publicKey != nil:
if trustRoot.rekorPublicKey != nil {
untrustedSET, ok := untrustedAnnotations[signature.SigstoreSETAnnotationKey]
if !ok { // For user convenience; passing an empty []byte to VerifyRekorSet should work.
return sarRejected, fmt.Errorf("missing %s annotation", signature.SigstoreSETAnnotationKey)
}
// We could use publicKeyPEM directly, but lets re-marshal to avoid inconsistencies.
// FIXME: We could just generate DER instead of the full PEM text
recreatedPublicKeyPEM, err := cryptoutils.MarshalPublicKeyToPEM(trustRoot.publicKey)
if err != nil {
// Coverage: The key was loaded from a PEM format, so its unclear how this could fail.
// (PEM is not essential, MarshalPublicKeyToPEM can only fail if marshaling to ASN1.DER fails.)
return sarRejected, fmt.Errorf("re-marshaling public key to PEM: %w", err)
}
// We dont care about the Rekor timestamp, just about log presence.
if _, err := internal.VerifyRekorSET(trustRoot.rekorPublicKey, []byte(untrustedSET), recreatedPublicKeyPEM, untrustedBase64Signature, untrustedPayload); err != nil {
return sarRejected, err
}
}
publicKey = trustRoot.publicKey
case trustRoot.fulcio != nil:
if trustRoot.rekorPublicKey == nil { // newPRSigstoreSigned rejects such combinations.
return sarRejected, errors.New("Internal inconsistency: Fulcio CA specified without a Rekor public key")
}
untrustedSET, ok := untrustedAnnotations[signature.SigstoreSETAnnotationKey]
if !ok { // For user convenience; passing an empty []byte to VerifyRekorSet should correctly reject it anyway.
return sarRejected, fmt.Errorf("missing %s annotation", signature.SigstoreSETAnnotationKey)
}
untrustedCert, ok := untrustedAnnotations[signature.SigstoreCertificateAnnotationKey]
if !ok { // For user convenience; passing an empty []byte to VerifyRekorSet should correctly reject it anyway.
return sarRejected, fmt.Errorf("missing %s annotation", signature.SigstoreCertificateAnnotationKey)
}
var untrustedIntermediateChainBytes []byte
if untrustedIntermediateChain, ok := untrustedAnnotations[signature.SigstoreIntermediateCertificateChainAnnotationKey]; ok {
untrustedIntermediateChainBytes = []byte(untrustedIntermediateChain)
}
pk, err := verifyRekorFulcio(trustRoot.rekorPublicKey, trustRoot.fulcio,
[]byte(untrustedSET), []byte(untrustedCert), untrustedIntermediateChainBytes, untrustedBase64Signature, untrustedPayload)
if err != nil {
return sarRejected, err
}
publicKey = pk
}
if publicKey == nil {
// Coverage: This should never happen, we have already excluded the possibility in the switch above.
return sarRejected, fmt.Errorf("Internal inconsistency: publicKey not set before verifying sigstore payload")
}
signature, err := internal.VerifySigstorePayload(publicKey, untrustedPayload, untrustedBase64Signature, internal.SigstorePayloadAcceptanceRules{
ValidateSignedDockerReference: func(ref string) error {
if !pr.SignedIdentity.matchesDockerReference(image, ref) {
return PolicyRequirementError(fmt.Sprintf("Signature for identity %s is not accepted", ref))

View File

@ -111,13 +111,24 @@ type prSignedBaseLayer struct {
type prSigstoreSigned struct {
prCommon
// KeyPath is a pathname to a local file containing the trusted key. Exactly one of KeyPath and KeyData must be specified.
// KeyPath is a pathname to a local file containing the trusted key. Exactly one of KeyPath, KeyData, Fulcio must be specified.
KeyPath string `json:"keyPath,omitempty"`
// KeyData contains the trusted key, base64-encoded. Exactly one of KeyPath and KeyData must be specified.
// KeyData contains the trusted key, base64-encoded. Exactly one of KeyPath, KeyData, Fulcio must be specified.
KeyData []byte `json:"keyData,omitempty"`
// FIXME: Multiple public keys?
// FIXME: Support fulcio+rekor as an alternative.
// Fulcio specifies which Fulcio-generated certificates are accepted. Exactly one of KeyPath, KeyData, Fulcio must be specified.
// If Fulcio is specified, one of RekorPublicKeyPath or RekorPublicKeyData must be specified as well.
Fulcio PRSigstoreSignedFulcio `json:"fulcio,omitempty"`
// RekorPublicKeyPath is a pathname to local file containing a public key of a Rekor server which must record acceptable signatures.
// If Fulcio is used, one of RekorPublicKeyPath or RekorPublicKeyData must be specified as well; otherwise it is optional
// (and Rekor inclusion is not required if a Rekor public key is not specified).
RekorPublicKeyPath string `json:"rekorPublicKeyPath,omitempty"`
// RekorPublicKeyPath contain a base64-encoded public key of a Rekor server which must record acceptable signatures.
// If Fulcio is used, one of RekorPublicKeyPath or RekorPublicKeyData must be specified as well; otherwise it is optional
// (and Rekor inclusion is not required if a Rekor public key is not specified).
RekorPublicKeyData []byte `json:"rekorPublicKeyData,omitempty"`
// SignedIdentity specifies what image identity the signature must be claiming about the image.
// Defaults to "matchRepoDigestOrExact" if not specified.
@ -125,6 +136,26 @@ type prSigstoreSigned struct {
SignedIdentity PolicyReferenceMatch `json:"signedIdentity"`
}
// PRSigstoreSignedFulcio contains Fulcio configuration options for a "sigstoreSigned" PolicyRequirement.
// This is a public type with a single private implementation.
type PRSigstoreSignedFulcio interface {
// toFulcioTrustRoot creates a fulcioTrustRoot from the input data.
// (This also prevents external implementations of this interface, ensuring that prSigstoreSignedFulcio is the only one.)
prepareTrustRoot() (*fulcioTrustRoot, error)
}
// prSigstoreSignedFulcio collects Fulcio configuration options for prSigstoreSigned
type prSigstoreSignedFulcio struct {
// CAPath a path to a file containing accepted CA root certificates, in PEM format. Exactly one of CAPath and CAData must be specified.
CAPath string `json:"caPath,omitempty"`
// CAData contains accepted CA root certificates in PEM format, all of that base64-encoded. Exactly one of CAPath and CAData must be specified.
CAData []byte `json:"caData,omitempty"`
// OIDCIssuer specifies the expected OIDC issuer, recorded by Fulcio into the generated certificates.
OIDCIssuer string `json:"oidcIssuer,omitempty"`
// SubjectEmail specifies the expected email address of the authenticated OIDC identity, recorded by Fulcio into the generated certificates.
SubjectEmail string `json:"subjectEmail,omitempty"`
}
// PolicyReferenceMatch specifies a set of image identities accepted in PolicyRequirement.
// The type is public, but its implementation is private.

View File

@ -10,6 +10,7 @@ import (
"errors"
"fmt"
"github.com/sigstore/sigstore/pkg/cryptoutils"
"github.com/sigstore/sigstore/pkg/signature"
"github.com/theupdateframework/go-tuf/encrypted"
)
@ -68,3 +69,31 @@ func loadPrivateKey(key []byte, pass []byte) (signature.SignerVerifier, error) {
return nil, errors.New("unsupported key type")
}
}
// simplified from sigstore/cosign/pkg/cosign.marshalKeyPair
// loadPrivateKey always requires a encryption, so this always requires a passphrase.
func marshalKeyPair(privateKey crypto.PrivateKey, publicKey crypto.PublicKey, password []byte) (_privateKey []byte, _publicKey []byte, err error) {
x509Encoded, err := x509.MarshalPKCS8PrivateKey(privateKey)
if err != nil {
return nil, nil, fmt.Errorf("x509 encoding private key: %w", err)
}
encBytes, err := encrypted.Encrypt(x509Encoded, password)
if err != nil {
return nil, nil, err
}
// store in PEM format
privBytes := pem.EncodeToMemory(&pem.Block{
Bytes: encBytes,
Type: sigstorePrivateKeyPemType,
})
// Now do the public key
pubBytes, err := cryptoutils.MarshalPublicKeyToPEM(publicKey)
if err != nil {
return nil, nil, err
}
return privBytes, pubBytes, nil
}

View File

@ -0,0 +1,35 @@
package sigstore
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
)
// GenerateKeyPairResult is a struct to ensure the private and public parts can not be confused by the caller.
type GenerateKeyPairResult struct {
PublicKey []byte
PrivateKey []byte
}
// GenerateKeyPair generates a public/private key pair usable for signing images using the sigstore format,
// and returns key representations suitable for storing in long-term files (with the private key encrypted using the provided passphrase).
// The specific key kind (e.g. algorithm, size), as well as the file format, are unspecified by this API,
// and can change with best practices over time.
func GenerateKeyPair(passphrase []byte) (*GenerateKeyPairResult, error) {
// https://github.com/sigstore/cosign/blob/main/specs/SIGNATURE_SPEC.md#signature-schemes
// only requires ECDSA-P256 to be supported, so thats what we must use.
rawKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
// Coverage: This can fail only if the randomness source fails
return nil, err
}
private, public, err := marshalKeyPair(rawKey, rawKey.Public(), passphrase)
if err != nil {
return nil, err
}
return &GenerateKeyPairResult{
PublicKey: public,
PrivateKey: private,
}, nil
}

View File

@ -11,7 +11,7 @@ const (
VersionPatch = 0
// VersionDev indicates development branch. Releases will be empty string.
VersionDev = "-dev"
VersionDev = ""
)
// Version is the specification version that the package types support.

View File

@ -1,3 +1,3 @@
## The libtrust Project Community Code of Conduct
The libtrust project follows the [Containers Community Code of Conduct](https://github.com/containers/common/blob/master/CODE-OF-CONDUCT.md).
The libtrust project follows the [Containers Community Code of Conduct](https://github.com/containers/common/blob/main/CODE-OF-CONDUCT.md).

View File

@ -1,3 +1,3 @@
## Security and Disclosure Information Policy for the libtrust Project
The libtrust Project follows the [Security and Disclosure Information Policy](https://github.com/containers/common/blob/master/SECURITY.md) for the Containers Projects.
The libtrust Project follows the [Security and Disclosure Information Policy](https://github.com/containers/common/blob/main/SECURITY.md) for the Containers Projects.

View File

@ -17,10 +17,11 @@
package blockcipher
import (
"errors"
"fmt"
"io"
"github.com/opencontainers/go-digest"
"github.com/pkg/errors"
)
// LayerCipherType is the ciphertype as specified in the layer metadata
@ -129,7 +130,7 @@ func (h *LayerBlockCipherHandler) Encrypt(plainDataReader io.Reader, typ LayerCi
}
return encDataReader, fin, err
}
return nil, nil, errors.Errorf("unsupported cipher type: %s", typ)
return nil, nil, fmt.Errorf("unsupported cipher type: %s", typ)
}
// Decrypt is the handler for the layer decryption routine
@ -141,7 +142,7 @@ func (h *LayerBlockCipherHandler) Decrypt(encDataReader io.Reader, opt LayerBloc
if c, ok := h.cipherMap[typ]; ok {
return c.Decrypt(encDataReader, opt)
}
return nil, LayerBlockCipherOptions{}, errors.Errorf("unsupported cipher type: %s", typ)
return nil, LayerBlockCipherOptions{}, fmt.Errorf("unsupported cipher type: %s", typ)
}
// NewLayerBlockCipherHandler returns a new default handler
@ -153,7 +154,7 @@ func NewLayerBlockCipherHandler() (*LayerBlockCipherHandler, error) {
var err error
h.cipherMap[AES256CTR], err = NewAESCTRLayerBlockCipher(256)
if err != nil {
return nil, errors.Wrap(err, "unable to set up Cipher AES-256-CTR")
return nil, fmt.Errorf("unable to set up Cipher AES-256-CTR: %w", err)
}
return &h, nil

View File

@ -22,12 +22,12 @@ import (
"crypto/hmac"
"crypto/rand"
"crypto/sha256"
"errors"
"fmt"
"hash"
"io"
"github.com/containers/ocicrypt/utils"
"github.com/pkg/errors"
)
// AESCTRLayerBlockCipher implements the AES CTR stream cipher
@ -74,7 +74,7 @@ func (r *aesctrcryptor) Read(p []byte) (int, error) {
if !r.bc.encrypt {
if _, err := r.bc.hmac.Write(p[:o]); err != nil {
r.bc.err = errors.Wrapf(err, "could not write to hmac")
r.bc.err = fmt.Errorf("could not write to hmac: %w", err)
return 0, r.bc.err
}
@ -92,7 +92,7 @@ func (r *aesctrcryptor) Read(p []byte) (int, error) {
if r.bc.encrypt {
if _, err := r.bc.hmac.Write(p[:o]); err != nil {
r.bc.err = errors.Wrapf(err, "could not write to hmac")
r.bc.err = fmt.Errorf("could not write to hmac: %w", err)
return 0, r.bc.err
}
@ -120,13 +120,13 @@ func (bc *AESCTRLayerBlockCipher) init(encrypt bool, reader io.Reader, opts Laye
if !ok {
nonce = make([]byte, aes.BlockSize)
if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
return LayerBlockCipherOptions{}, errors.Wrap(err, "unable to generate random nonce")
return LayerBlockCipherOptions{}, fmt.Errorf("unable to generate random nonce: %w", err)
}
}
block, err := aes.NewCipher(key)
if err != nil {
return LayerBlockCipherOptions{}, errors.Wrap(err, "aes.NewCipher failed")
return LayerBlockCipherOptions{}, fmt.Errorf("aes.NewCipher failed: %w", err)
}
bc.reader = reader

View File

@ -17,10 +17,11 @@
package config
import (
"errors"
"fmt"
"strings"
"github.com/containers/ocicrypt/crypto/pkcs11"
"github.com/pkg/errors"
"gopkg.in/yaml.v3"
)
@ -85,7 +86,7 @@ func EncryptWithPkcs11(pkcs11Config *pkcs11.Pkcs11Config, pkcs11Pubkeys, pkcs11Y
}
p11confYaml, err := yaml.Marshal(pkcs11Config)
if err != nil {
return CryptoConfig{}, errors.Wrapf(err, "Could not marshal Pkcs11Config to Yaml")
return CryptoConfig{}, fmt.Errorf("Could not marshal Pkcs11Config to Yaml: %w", err)
}
dc = DecryptConfig{
@ -223,7 +224,7 @@ func DecryptWithGpgPrivKeys(gpgPrivKeys, gpgPrivKeysPwds [][]byte) (CryptoConfig
func DecryptWithPkcs11Yaml(pkcs11Config *pkcs11.Pkcs11Config, pkcs11Yamls [][]byte) (CryptoConfig, error) {
p11confYaml, err := yaml.Marshal(pkcs11Config)
if err != nil {
return CryptoConfig{}, errors.Wrapf(err, "Could not marshal Pkcs11Config to Yaml")
return CryptoConfig{}, fmt.Errorf("Could not marshal Pkcs11Config to Yaml: %w", err)
}
dc := DecryptConfig{

View File

@ -18,9 +18,8 @@ package config
import (
"encoding/json"
"fmt"
"os"
"github.com/pkg/errors"
)
// Command describes the structure of command, it consist of path and args, where path defines the location of
@ -72,7 +71,7 @@ func GetConfiguration() (*OcicryptConfig, error) {
if len(filename) > 0 {
ic, err = parseConfigFile(filename)
if err != nil {
return nil, errors.Wrap(err, "Error while parsing keyprovider config file")
return nil, fmt.Errorf("Error while parsing keyprovider config file: %w", err)
}
} else {
return nil, nil

View File

@ -17,12 +17,12 @@
package pkcs11config
import (
"errors"
"fmt"
"os"
"path"
"github.com/containers/ocicrypt/crypto/pkcs11"
"github.com/pkg/errors"
"gopkg.in/yaml.v3"
)

View File

@ -16,7 +16,6 @@ package pkcs11
import (
"fmt"
"github.com/pkg/errors"
pkcs11uri "github.com/stefanberger/go-pkcs11uri"
"gopkg.in/yaml.v3"
)
@ -43,7 +42,7 @@ func ParsePkcs11Uri(uri string) (*pkcs11uri.Pkcs11URI, error) {
p11uri := pkcs11uri.New()
err := p11uri.Parse(uri)
if err != nil {
return nil, errors.Wrapf(err, "Could not parse Pkcs11URI from file")
return nil, fmt.Errorf("Could not parse Pkcs11URI from file: %w", err)
}
return p11uri, err
}
@ -58,7 +57,7 @@ func ParsePkcs11KeyFile(yamlstr []byte) (*Pkcs11KeyFileObject, error) {
err := yaml.Unmarshal(yamlstr, &p11keyfile)
if err != nil {
return nil, errors.Wrapf(err, "Could not unmarshal pkcs11 keyfile")
return nil, fmt.Errorf("Could not unmarshal pkcs11 keyfile: %w", err)
}
p11uri, err := ParsePkcs11Uri(p11keyfile.Pkcs11.Uri)
@ -129,7 +128,7 @@ func ParsePkcs11ConfigFile(yamlstr []byte) (*Pkcs11Config, error) {
err := yaml.Unmarshal(yamlstr, &p11conf)
if err != nil {
return &p11conf, errors.Wrapf(err, "Could not parse Pkcs11Config")
return &p11conf, fmt.Errorf("Could not parse Pkcs11Config: %w", err)
}
return &p11conf, nil
}

View File

@ -26,6 +26,7 @@ import (
"crypto/sha256"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"hash"
"net/url"
@ -34,7 +35,6 @@ import (
"strings"
"github.com/miekg/pkcs11"
"github.com/pkg/errors"
pkcs11uri "github.com/stefanberger/go-pkcs11uri"
)
@ -77,11 +77,11 @@ func rsaPublicEncryptOAEP(pubKey *rsa.PublicKey, plaintext []byte) ([]byte, stri
hashfunc = sha256.New()
hashalg = "sha256"
default:
return nil, "", errors.Errorf("Unsupported OAEP hash '%s'", oaephash)
return nil, "", fmt.Errorf("Unsupported OAEP hash '%s'", oaephash)
}
ciphertext, err := rsa.EncryptOAEP(hashfunc, rand.Reader, pubKey, plaintext, OAEPLabel)
if err != nil {
return nil, "", errors.Wrapf(err, "rss.EncryptOAEP failed")
return nil, "", fmt.Errorf("rss.EncryptOAEP failed: %w", err)
}
return ciphertext, hashalg, nil
@ -105,7 +105,7 @@ func pkcs11UriGetLoginParameters(p11uri *pkcs11uri.Pkcs11URI, privateKeyOperatio
module, err := p11uri.GetModule()
if err != nil {
return "", "", 0, errors.Wrap(err, "No module available in pkcs11 URI")
return "", "", 0, fmt.Errorf("No module available in pkcs11 URI: %w", err)
}
slotid := int64(-1)
@ -114,7 +114,7 @@ func pkcs11UriGetLoginParameters(p11uri *pkcs11uri.Pkcs11URI, privateKeyOperatio
if ok {
slotid, err = strconv.ParseInt(slot, 10, 64)
if err != nil {
return "", "", 0, errors.Wrap(err, "slot-id is not a valid number")
return "", "", 0, fmt.Errorf("slot-id is not a valid number: %w", err)
}
if slotid < 0 {
return "", "", 0, fmt.Errorf("slot-id is a negative number")
@ -141,13 +141,13 @@ func pkcs11UriGetKeyIdAndLabel(p11uri *pkcs11uri.Pkcs11URI) (string, string, err
func pkcs11OpenSession(p11ctx *pkcs11.Ctx, slotid uint, pin string) (session pkcs11.SessionHandle, err error) {
session, err = p11ctx.OpenSession(slotid, pkcs11.CKF_SERIAL_SESSION|pkcs11.CKF_RW_SESSION)
if err != nil {
return 0, errors.Wrapf(err, "OpenSession to slot %d failed", slotid)
return 0, fmt.Errorf("OpenSession to slot %d failed: %w", slotid, err)
}
if len(pin) > 0 {
err = p11ctx.Login(session, pkcs11.CKU_USER, pin)
if err != nil {
_ = p11ctx.CloseSession(session)
return 0, errors.Wrap(err, "Could not login to device")
return 0, fmt.Errorf("Could not login to device: %w", err)
}
}
return session, nil
@ -171,7 +171,7 @@ func pkcs11UriLogin(p11uri *pkcs11uri.Pkcs11URI, privateKeyOperation bool) (ctx
if err != nil {
p11Err := err.(pkcs11.Error)
if p11Err != pkcs11.CKR_CRYPTOKI_ALREADY_INITIALIZED {
return nil, 0, errors.Wrap(err, "Initialize failed")
return nil, 0, fmt.Errorf("Initialize failed: %w", err)
}
}
@ -182,7 +182,7 @@ func pkcs11UriLogin(p11uri *pkcs11uri.Pkcs11URI, privateKeyOperation bool) (ctx
slots, err := p11ctx.GetSlotList(true)
if err != nil {
return nil, 0, errors.Wrap(err, "GetSlotList failed")
return nil, 0, fmt.Errorf("GetSlotList failed: %w", err)
}
tokenlabel, ok := p11uri.GetPathAttribute("token", false)
@ -234,24 +234,24 @@ func findObject(p11ctx *pkcs11.Ctx, session pkcs11.SessionHandle, class uint, ke
}
if err := p11ctx.FindObjectsInit(session, template); err != nil {
return 0, errors.Wrap(err, "FindObjectsInit failed")
return 0, fmt.Errorf("FindObjectsInit failed: %w", err)
}
obj, _, err := p11ctx.FindObjects(session, 100)
if err != nil {
return 0, errors.Wrap(err, "FindObjects failed")
return 0, fmt.Errorf("FindObjects failed: %w", err)
}
if err := p11ctx.FindObjectsFinal(session); err != nil {
return 0, errors.Wrap(err, "FindObjectsFinal failed")
return 0, fmt.Errorf("FindObjectsFinal failed: %w", err)
}
if len(obj) > 1 {
return 0, errors.Errorf("There are too many (=%d) keys with %s", len(obj), msg)
return 0, fmt.Errorf("There are too many (=%d) keys with %s", len(obj), msg)
} else if len(obj) == 1 {
return obj[0], nil
}
return 0, errors.Errorf("Could not find any object with %s", msg)
return 0, fmt.Errorf("Could not find any object with %s", msg)
}
// publicEncryptOAEP uses a public key described by a pkcs11 URI to OAEP encrypt the given plaintext
@ -291,17 +291,17 @@ func publicEncryptOAEP(pubKey *Pkcs11KeyFileObject, plaintext []byte) ([]byte, s
oaep = OAEPSha256Params
hashalg = "sha256"
default:
return nil, "", errors.Errorf("Unsupported OAEP hash '%s'", oaephash)
return nil, "", fmt.Errorf("Unsupported OAEP hash '%s'", oaephash)
}
err = p11ctx.EncryptInit(session, []*pkcs11.Mechanism{pkcs11.NewMechanism(pkcs11.CKM_RSA_PKCS_OAEP, oaep)}, p11PubKey)
if err != nil {
return nil, "", errors.Wrap(err, "EncryptInit error")
return nil, "", fmt.Errorf("EncryptInit error: %w", err)
}
ciphertext, err := p11ctx.Encrypt(session, plaintext)
if err != nil {
return nil, "", errors.Wrap(err, "Encrypt failed")
return nil, "", fmt.Errorf("Encrypt failed: %w", err)
}
return ciphertext, hashalg, nil
}
@ -339,16 +339,16 @@ func privateDecryptOAEP(privKeyObj *Pkcs11KeyFileObject, ciphertext []byte, hash
case "sha256":
oaep = OAEPSha256Params
default:
return nil, errors.Errorf("Unsupported hash algorithm '%s' for decryption", hashalg)
return nil, fmt.Errorf("Unsupported hash algorithm '%s' for decryption", hashalg)
}
err = p11ctx.DecryptInit(session, []*pkcs11.Mechanism{pkcs11.NewMechanism(pkcs11.CKM_RSA_PKCS_OAEP, oaep)}, p11PrivKey)
if err != nil {
return nil, errors.Wrapf(err, "DecryptInit failed")
return nil, fmt.Errorf("DecryptInit failed: %w", err)
}
plaintext, err := p11ctx.Decrypt(session, ciphertext)
if err != nil {
return nil, errors.Wrapf(err, "Decrypt failed")
return nil, fmt.Errorf("Decrypt failed: %w", err)
}
return plaintext, err
}
@ -403,7 +403,7 @@ func EncryptMultiple(pubKeys []interface{}, data []byte) ([]byte, error) {
case *Pkcs11KeyFileObject:
ciphertext, hashalg, err = publicEncryptOAEP(pkey, data)
default:
err = errors.Errorf("Unsupported key object type for pkcs11 public key")
err = fmt.Errorf("Unsupported key object type for pkcs11 public key")
}
if err != nil {
return nil, err
@ -442,13 +442,13 @@ func Decrypt(privKeyObjs []*Pkcs11KeyFileObject, pkcs11blobstr []byte) ([]byte,
pkcs11blob := Pkcs11Blob{}
err := json.Unmarshal(pkcs11blobstr, &pkcs11blob)
if err != nil {
return nil, errors.Wrapf(err, "Could not parse Pkcs11Blob")
return nil, fmt.Errorf("Could not parse Pkcs11Blob: %w", err)
}
switch pkcs11blob.Version {
case 0:
// latest supported version
default:
return nil, errors.Errorf("found Pkcs11Blob with version %d but maximum supported version is 0", pkcs11blob.Version)
return nil, fmt.Errorf("found Pkcs11Blob with version %d but maximum supported version is 0", pkcs11blob.Version)
}
// since we do trial and error, collect all encountered errors
errs := ""
@ -458,7 +458,7 @@ func Decrypt(privKeyObjs []*Pkcs11KeyFileObject, pkcs11blobstr []byte) ([]byte,
case 0:
// last supported version
default:
return nil, errors.Errorf("found Pkcs11Recipient with version %d but maximum supported version is 0", recipient.Version)
return nil, fmt.Errorf("found Pkcs11Recipient with version %d but maximum supported version is 0", recipient.Version)
}
ciphertext, err := base64.StdEncoding.DecodeString(recipient.Blob)
@ -481,5 +481,5 @@ func Decrypt(privKeyObjs []*Pkcs11KeyFileObject, pkcs11blobstr []byte) ([]byte,
}
}
return nil, errors.Errorf("Could not find a pkcs11 key for decryption:\n%s", errs)
return nil, fmt.Errorf("Could not find a pkcs11 key for decryption:\n%s", errs)
}

View File

@ -1,3 +1,4 @@
//go:build !cgo
// +build !cgo
/*
@ -18,14 +19,12 @@
package pkcs11
import (
"github.com/pkg/errors"
)
import "fmt"
func EncryptMultiple(pubKeys []interface{}, data []byte) ([]byte, error) {
return nil, errors.Errorf("ocicrypt pkcs11 not supported on this build")
return nil, fmt.Errorf("ocicrypt pkcs11 not supported on this build")
}
func Decrypt(privKeyObjs []*Pkcs11KeyFileObject, pkcs11blobstr []byte) ([]byte, error) {
return nil, errors.Errorf("ocicrypt pkcs11 not supported on this build")
return nil, fmt.Errorf("ocicrypt pkcs11 not supported on this build")
}

View File

@ -17,12 +17,11 @@
package pkcs11
import (
"fmt"
"os"
"runtime"
"strings"
"sync"
"github.com/pkg/errors"
)
var (
@ -45,7 +44,7 @@ func setEnvVars(env map[string]string) ([]string, error) {
err := os.Setenv(k, v)
if err != nil {
restoreEnv(oldenv)
return nil, errors.Wrapf(err, "Could not set environment variable '%s' to '%s'", k, v)
return nil, fmt.Errorf("Could not set environment variable '%s' to '%s': %w", k, v, err)
}
}

View File

@ -19,6 +19,7 @@ package ocicrypt
import (
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"io"
"strings"
@ -34,7 +35,6 @@ import (
"github.com/containers/ocicrypt/keywrap/pkcs7"
"github.com/opencontainers/go-digest"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
log "github.com/sirupsen/logrus"
)
@ -133,11 +133,11 @@ func EncryptLayer(ec *config.EncryptConfig, encOrPlainLayerReader io.Reader, des
}
privOptsData, err = json.Marshal(opts.Private)
if err != nil {
return nil, errors.Wrapf(err, "could not JSON marshal opts")
return nil, fmt.Errorf("could not JSON marshal opts: %w", err)
}
pubOptsData, err = json.Marshal(opts.Public)
if err != nil {
return nil, errors.Wrapf(err, "could not JSON marshal opts")
return nil, fmt.Errorf("could not JSON marshal opts: %w", err)
}
}
@ -243,9 +243,9 @@ func decryptLayerKeyOptsData(dc *config.DecryptConfig, desc ocispec.Descriptor)
}
}
if !privKeyGiven {
return nil, errors.Errorf("missing private key needed for decryption:\n%s", errs)
return nil, fmt.Errorf("missing private key needed for decryption:\n%s", errs)
}
return nil, errors.Errorf("no suitable key unwrapper found or none of the private keys could be used for decryption:\n%s", errs)
return nil, fmt.Errorf("no suitable key unwrapper found or none of the private keys could be used for decryption:\n%s", errs)
}
func getLayerPubOpts(desc ocispec.Descriptor) ([]byte, error) {
@ -276,7 +276,7 @@ func preUnwrapKey(keywrapper keywrap.KeyWrapper, dc *config.DecryptConfig, b64An
}
return optsData, nil
}
return nil, errors.Errorf("no suitable key found for decrypting layer key:\n%s", errs)
return nil, fmt.Errorf("no suitable key found for decrypting layer key:\n%s", errs)
}
// commonEncryptLayer is a function to encrypt the plain layer using a new random
@ -311,7 +311,7 @@ func commonDecryptLayer(encLayerReader io.Reader, privOptsData []byte, pubOptsDa
privOpts := blockcipher.PrivateLayerBlockCipherOptions{}
err := json.Unmarshal(privOptsData, &privOpts)
if err != nil {
return nil, "", errors.Wrapf(err, "could not JSON unmarshal privOptsData")
return nil, "", fmt.Errorf("could not JSON unmarshal privOptsData: %w", err)
}
lbch, err := blockcipher.NewLayerBlockCipherHandler()
@ -323,7 +323,7 @@ func commonDecryptLayer(encLayerReader io.Reader, privOptsData []byte, pubOptsDa
if len(pubOptsData) > 0 {
err := json.Unmarshal(pubOptsData, &pubOpts)
if err != nil {
return nil, "", errors.Wrapf(err, "could not JSON unmarshal pubOptsData")
return nil, "", fmt.Errorf("could not JSON unmarshal pubOptsData: %w", err)
}
}

View File

@ -17,6 +17,7 @@
package ocicrypt
import (
"errors"
"fmt"
"io"
"os"
@ -27,7 +28,6 @@ import (
"sync"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
"golang.org/x/term"
)
@ -133,7 +133,7 @@ func (gc *gpgv2Client) GetGPGPrivateKey(keyid uint64, passphrase string) ([]byte
rfile, wfile, err := os.Pipe()
if err != nil {
return nil, errors.Wrapf(err, "could not create pipe")
return nil, fmt.Errorf("could not create pipe: %w", err)
}
defer func() {
rfile.Close()
@ -359,7 +359,7 @@ func GPGGetPrivateKey(descs []ocispec.Descriptor, gpgClient GPGClient, gpgVault
}
keywrapper := GetKeyWrapper(scheme)
if keywrapper == nil {
return nil, nil, errors.Errorf("could not get KeyWrapper for %s", scheme)
return nil, nil, fmt.Errorf("could not get KeyWrapper for %s", scheme)
}
keyIds, err := keywrapper.GetKeyIdsFromPacket(b64pgpPackets)
if err != nil {
@ -418,7 +418,7 @@ func GPGGetPrivateKey(descs []ocispec.Descriptor, gpgClient GPGClient, gpgVault
if !found && len(b64pgpPackets) > 0 && mustFindKey {
ids := uint64ToStringArray("0x%x", keyIds)
return nil, nil, errors.Errorf("missing key for decryption of layer %x of %s. Need one of the following keys: %s", desc.Digest, desc.Platform, strings.Join(ids, ", "))
return nil, nil, fmt.Errorf("missing key for decryption of layer %x of %s. Need one of the following keys: %s", desc.Digest, desc.Platform, strings.Join(ids, ", "))
}
}
}

View File

@ -18,9 +18,9 @@ package ocicrypt
import (
"bytes"
"fmt"
"os"
"github.com/pkg/errors"
"golang.org/x/crypto/openpgp"
"golang.org/x/crypto/openpgp/packet"
)
@ -55,7 +55,7 @@ func (g *gpgVault) AddSecretKeyRingData(gpgSecretKeyRingData []byte) error {
r := bytes.NewReader(gpgSecretKeyRingData)
entityList, err := openpgp.ReadKeyRing(r)
if err != nil {
return errors.Wrapf(err, "could not read keyring")
return fmt.Errorf("could not read keyring: %w", err)
}
g.entityLists = append(g.entityLists, entityList)
g.keyDataList = append(g.keyDataList, gpgSecretKeyRingData)

View File

@ -1,6 +1,7 @@
package helpers
import (
"errors"
"fmt"
"os"
"strconv"
@ -11,8 +12,6 @@ import (
"github.com/containers/ocicrypt/config/pkcs11config"
"github.com/containers/ocicrypt/crypto/pkcs11"
encutils "github.com/containers/ocicrypt/utils"
"github.com/pkg/errors"
)
// processRecipientKeys sorts the array of recipients by type. Recipients may be either
@ -44,7 +43,7 @@ func processRecipientKeys(recipients []string) ([][]byte, [][]byte, [][]byte, []
case "jwe":
tmp, err := os.ReadFile(value)
if err != nil {
return nil, nil, nil, nil, nil, nil, errors.Wrap(err, "Unable to read file")
return nil, nil, nil, nil, nil, nil, fmt.Errorf("Unable to read file: %w", err)
}
if !encutils.IsPublicKey(tmp) {
return nil, nil, nil, nil, nil, nil, errors.New("File provided is not a public key")
@ -54,7 +53,7 @@ func processRecipientKeys(recipients []string) ([][]byte, [][]byte, [][]byte, []
case "pkcs7":
tmp, err := os.ReadFile(value)
if err != nil {
return nil, nil, nil, nil, nil, nil, errors.Wrap(err, "Unable to read file")
return nil, nil, nil, nil, nil, nil, fmt.Errorf("Unable to read file: %w", err)
}
if !encutils.IsCertificate(tmp) {
return nil, nil, nil, nil, nil, nil, errors.New("File provided is not an x509 cert")
@ -64,7 +63,7 @@ func processRecipientKeys(recipients []string) ([][]byte, [][]byte, [][]byte, []
case "pkcs11":
tmp, err := os.ReadFile(value)
if err != nil {
return nil, nil, nil, nil, nil, nil, errors.Wrap(err, "Unable to read file")
return nil, nil, nil, nil, nil, nil, fmt.Errorf("Unable to read file: %w", err)
}
if encutils.IsPkcs11PublicKey(tmp) {
pkcs11Yamls = append(pkcs11Yamls, tmp)
@ -94,7 +93,7 @@ func processx509Certs(keys []string) ([][]byte, error) {
}
tmp, err := os.ReadFile(fileName)
if err != nil {
return nil, errors.Wrap(err, "Unable to read file")
return nil, fmt.Errorf("Unable to read file: %w", err)
}
if !encutils.IsCertificate(tmp) {
continue
@ -119,7 +118,7 @@ func processPwdString(pwdString string) ([]byte, error) {
fdStr := pwdString[3:]
fd, err := strconv.Atoi(fdStr)
if err != nil {
return nil, errors.Wrapf(err, "could not parse file descriptor %s", fdStr)
return nil, fmt.Errorf("could not parse file descriptor %s: %w", fdStr, err)
}
f := os.NewFile(uintptr(fd), "pwdfile")
if f == nil {
@ -129,7 +128,7 @@ func processPwdString(pwdString string) ([]byte, error) {
pwd := make([]byte, 64)
n, err := f.Read(pwd)
if err != nil {
return nil, errors.Wrapf(err, "could not read from file descriptor")
return nil, fmt.Errorf("could not read from file descriptor: %w", err)
}
return pwd[:n], nil
}

View File

@ -18,11 +18,12 @@ package jwe
import (
"crypto/ecdsa"
"errors"
"fmt"
"github.com/containers/ocicrypt/config"
"github.com/containers/ocicrypt/keywrap"
"github.com/containers/ocicrypt/utils"
"github.com/pkg/errors"
jose "gopkg.in/square/go-jose.v2"
)
@ -54,11 +55,11 @@ func (kw *jweKeyWrapper) WrapKeys(ec *config.EncryptConfig, optsData []byte) ([]
encrypter, err := jose.NewMultiEncrypter(jose.A256GCM, joseRecipients, nil)
if err != nil {
return nil, errors.Wrapf(err, "jose.NewMultiEncrypter failed")
return nil, fmt.Errorf("jose.NewMultiEncrypter failed: %w", err)
}
jwe, err := encrypter.Encrypt(optsData)
if err != nil {
return nil, errors.Wrapf(err, "JWE Encrypt failed")
return nil, fmt.Errorf("JWE Encrypt failed: %w", err)
}
return []byte(jwe.FullSerialize()), nil
}

View File

@ -19,13 +19,14 @@ package keyprovider
import (
"context"
"encoding/json"
"errors"
"fmt"
"github.com/containers/ocicrypt/config"
keyproviderconfig "github.com/containers/ocicrypt/config/keyprovider-config"
"github.com/containers/ocicrypt/keywrap"
"github.com/containers/ocicrypt/utils"
keyproviderpb "github.com/containers/ocicrypt/utils/keyprovider"
"github.com/pkg/errors"
log "github.com/sirupsen/logrus"
"google.golang.org/grpc"
)
@ -113,13 +114,13 @@ func (kw *keyProviderKeyWrapper) WrapKeys(ec *config.EncryptConfig, optsData []b
if kw.attrs.Command != nil {
protocolOuput, err := getProviderCommandOutput(input, kw.attrs.Command)
if err != nil {
return nil, errors.Wrap(err, "error while retrieving keyprovider protocol command output")
return nil, fmt.Errorf("error while retrieving keyprovider protocol command output: %w", err)
}
return protocolOuput.KeyWrapResults.Annotation, nil
} else if kw.attrs.Grpc != "" {
protocolOuput, err := getProviderGRPCOutput(input, kw.attrs.Grpc, OpKeyWrap)
if err != nil {
return nil, errors.Wrap(err, "error while retrieving keyprovider protocol grpc output")
return nil, fmt.Errorf("error while retrieving keyprovider protocol grpc output: %w", err)
}
return protocolOuput.KeyWrapResults.Annotation, nil
@ -171,7 +172,7 @@ func getProviderGRPCOutput(input []byte, connString string, operation KeyProvide
var grpcOutput *keyproviderpb.KeyProviderKeyWrapProtocolOutput
cc, err := grpc.Dial(connString, grpc.WithInsecure())
if err != nil {
return nil, errors.Wrap(err, "error while dialing rpc server")
return nil, fmt.Errorf("error while dialing rpc server: %w", err)
}
defer func() {
derr := cc.Close()
@ -188,12 +189,12 @@ func getProviderGRPCOutput(input []byte, connString string, operation KeyProvide
if operation == OpKeyWrap {
grpcOutput, err = client.WrapKey(context.Background(), req)
if err != nil {
return nil, errors.Wrap(err, "Error from grpc method")
return nil, fmt.Errorf("Error from grpc method: %w", err)
}
} else if operation == OpKeyUnwrap {
grpcOutput, err = client.UnWrapKey(context.Background(), req)
if err != nil {
return nil, errors.Wrap(err, "Error from grpc method")
return nil, fmt.Errorf("Error from grpc method: %w", err)
}
} else {
return nil, errors.New("Unsupported operation")
@ -202,7 +203,7 @@ func getProviderGRPCOutput(input []byte, connString string, operation KeyProvide
respBytes := grpcOutput.GetKeyProviderKeyWrapProtocolOutput()
err = json.Unmarshal(respBytes, &protocolOuput)
if err != nil {
return nil, errors.Wrap(err, "Error while unmarshalling grpc method output")
return nil, fmt.Errorf("Error while unmarshalling grpc method output: %w", err)
}
return &protocolOuput, nil
@ -217,7 +218,7 @@ func getProviderCommandOutput(input []byte, command *keyproviderconfig.Command)
}
err = json.Unmarshal(respBytes, &protocolOuput)
if err != nil {
return nil, errors.Wrap(err, "Error while unmarshalling binary executable command output")
return nil, fmt.Errorf("Error while unmarshalling binary executable command output: %w", err)
}
return &protocolOuput, nil
}

View File

@ -21,6 +21,7 @@ import (
"crypto"
"crypto/rand"
"encoding/base64"
"errors"
"fmt"
"io"
"net/mail"
@ -29,7 +30,6 @@ import (
"github.com/containers/ocicrypt/config"
"github.com/containers/ocicrypt/keywrap"
"github.com/pkg/errors"
"golang.org/x/crypto/openpgp"
"golang.org/x/crypto/openpgp/packet"
)
@ -63,7 +63,7 @@ func (kw *gpgKeyWrapper) WrapKeys(ec *config.EncryptConfig, optsData []byte) ([]
ciphertext := new(bytes.Buffer)
el, err := kw.createEntityList(ec)
if err != nil {
return nil, errors.Wrap(err, "unable to create entity list")
return nil, fmt.Errorf("unable to create entity list: %w", err)
}
if len(el) == 0 {
// nothing to do -- not an error
@ -99,7 +99,7 @@ func (kw *gpgKeyWrapper) UnwrapKey(dc *config.DecryptConfig, pgpPacket []byte) (
r := bytes.NewBuffer(pgpPrivateKey)
entityList, err := openpgp.ReadKeyRing(r)
if err != nil {
return nil, errors.Wrap(err, "unable to parse private keys")
return nil, fmt.Errorf("unable to parse private keys: %w", err)
}
var prompt openpgp.PromptFunction
@ -141,7 +141,7 @@ func (kw *gpgKeyWrapper) GetKeyIdsFromPacket(b64pgpPackets string) ([]uint64, er
for _, b64pgpPacket := range strings.Split(b64pgpPackets, ",") {
pgpPacket, err := base64.StdEncoding.DecodeString(b64pgpPacket)
if err != nil {
return nil, errors.Wrapf(err, "could not decode base64 encoded PGP packet")
return nil, fmt.Errorf("could not decode base64 encoded PGP packet: %w", err)
}
newids, err := kw.getKeyIDs(pgpPacket)
if err != nil {
@ -165,7 +165,7 @@ ParsePackets:
break ParsePackets
}
if err != nil {
return []uint64{}, errors.Wrapf(err, "packets.Next() failed")
return []uint64{}, fmt.Errorf("packets.Next() failed: %w", err)
}
switch p := p.(type) {
case *packet.EncryptedKey:

View File

@ -17,12 +17,13 @@
package pkcs11
import (
"errors"
"fmt"
"github.com/containers/ocicrypt/config"
"github.com/containers/ocicrypt/crypto/pkcs11"
"github.com/containers/ocicrypt/keywrap"
"github.com/containers/ocicrypt/utils"
"github.com/pkg/errors"
)
type pkcs11KeyWrapper struct {
@ -51,7 +52,7 @@ func (kw *pkcs11KeyWrapper) WrapKeys(ec *config.EncryptConfig, optsData []byte)
jsonString, err := pkcs11.EncryptMultiple(pkcs11Recipients, optsData)
if err != nil {
return nil, errors.Wrapf(err, "PKCS11 EncryptMulitple failed")
return nil, fmt.Errorf("PKCS11 EncryptMulitple failed: %w", err)
}
return jsonString, nil
}
@ -91,7 +92,7 @@ func (kw *pkcs11KeyWrapper) UnwrapKey(dc *config.DecryptConfig, jsonString []byt
return plaintext, nil
}
return nil, errors.Wrapf(err, "PKCS11: No suitable private key found for decryption")
return nil, fmt.Errorf("PKCS11: No suitable private key found for decryption: %w", err)
}
func (kw *pkcs11KeyWrapper) NoPossibleKeys(dcparameters map[string][][]byte) bool {

View File

@ -19,11 +19,12 @@ package pkcs7
import (
"crypto"
"crypto/x509"
"errors"
"fmt"
"github.com/containers/ocicrypt/config"
"github.com/containers/ocicrypt/keywrap"
"github.com/containers/ocicrypt/utils"
"github.com/pkg/errors"
"go.mozilla.org/pkcs7"
)
@ -104,7 +105,7 @@ func (kw *pkcs7KeyWrapper) UnwrapKey(dc *config.DecryptConfig, pkcs7Packet []byt
p7, err := pkcs7.Parse(pkcs7Packet)
if err != nil {
return nil, errors.Wrapf(err, "could not parse PKCS7 packet")
return nil, fmt.Errorf("could not parse PKCS7 packet: %w", err)
}
for idx, privKey := range privKeys {

View File

@ -18,10 +18,9 @@ package utils
import (
"bytes"
"fmt"
"io"
"os/exec"
"github.com/pkg/errors"
)
// FillBuffer fills the given buffer with as many bytes from the reader as possible. It returns
@ -53,7 +52,7 @@ func (r Runner) Exec(cmdName string, args []string, input []byte) ([]byte, error
cmd.Stderr = &stderr
err := cmd.Run()
if err != nil {
return nil, errors.Wrapf(err, "Error while running command: %s. stderr: %s", cmdName, stderr.String())
return nil, fmt.Errorf("Error while running command: %s. stderr: %s: %w", cmdName, stderr.String(), err)
}
return out.Bytes(), nil
}

View File

@ -24,17 +24,16 @@ import (
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"fmt"
"math/big"
"time"
"github.com/pkg/errors"
)
// CreateRSAKey creates an RSA key
func CreateRSAKey(bits int) (*rsa.PrivateKey, error) {
key, err := rsa.GenerateKey(rand.Reader, bits)
if err != nil {
return nil, errors.Wrap(err, "rsa.GenerateKey failed")
return nil, fmt.Errorf("rsa.GenerateKey failed: %w", err)
}
return key, nil
}
@ -49,7 +48,7 @@ func CreateRSATestKey(bits int, password []byte, pemencode bool) ([]byte, []byte
pubData, err := x509.MarshalPKIXPublicKey(&key.PublicKey)
if err != nil {
return nil, nil, errors.Wrap(err, "x509.MarshalPKIXPublicKey failed")
return nil, nil, fmt.Errorf("x509.MarshalPKIXPublicKey failed: %w", err)
}
privData := x509.MarshalPKCS1PrivateKey(key)
@ -69,7 +68,7 @@ func CreateRSATestKey(bits int, password []byte, pemencode bool) ([]byte, []byte
if len(password) > 0 {
block, err = x509.EncryptPEMBlock(rand.Reader, typ, privData, password, x509.PEMCipherAES256) //nolint:staticcheck // ignore SA1019, which is kept for backward compatibility
if err != nil {
return nil, nil, errors.Wrap(err, "x509.EncryptPEMBlock failed")
return nil, nil, fmt.Errorf("x509.EncryptPEMBlock failed: %w", err)
}
} else {
block = &pem.Block{
@ -88,17 +87,17 @@ func CreateRSATestKey(bits int, password []byte, pemencode bool) ([]byte, []byte
func CreateECDSATestKey(curve elliptic.Curve) ([]byte, []byte, error) {
key, err := ecdsa.GenerateKey(curve, rand.Reader)
if err != nil {
return nil, nil, errors.Wrapf(err, "ecdsa.GenerateKey failed")
return nil, nil, fmt.Errorf("ecdsa.GenerateKey failed: %w", err)
}
pubData, err := x509.MarshalPKIXPublicKey(&key.PublicKey)
if err != nil {
return nil, nil, errors.Wrapf(err, "x509.MarshalPKIXPublicKey failed")
return nil, nil, fmt.Errorf("x509.MarshalPKIXPublicKey failed: %w", err)
}
privData, err := x509.MarshalECPrivateKey(key)
if err != nil {
return nil, nil, errors.Wrapf(err, "x509.MarshalECPrivateKey failed")
return nil, nil, fmt.Errorf("x509.MarshalECPrivateKey failed: %w", err)
}
return pubData, privData, nil
@ -108,7 +107,7 @@ func CreateECDSATestKey(curve elliptic.Curve) ([]byte, []byte, error) {
func CreateTestCA() (*rsa.PrivateKey, *x509.Certificate, error) {
key, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
return nil, nil, errors.Wrap(err, "rsa.GenerateKey failed")
return nil, nil, fmt.Errorf("rsa.GenerateKey failed: %w", err)
}
ca := &x509.Certificate{
@ -154,12 +153,12 @@ func certifyKey(pub interface{}, template *x509.Certificate, caKey *rsa.PrivateK
certDER, err := x509.CreateCertificate(rand.Reader, template, caCert, pub, caKey)
if err != nil {
return nil, errors.Wrap(err, "x509.CreateCertificate failed")
return nil, fmt.Errorf("x509.CreateCertificate failed: %w", err)
}
cert, err := x509.ParseCertificate(certDER)
if err != nil {
return nil, errors.Wrap(err, "x509.ParseCertificate failed")
return nil, fmt.Errorf("x509.ParseCertificate failed: %w", err)
}
return cert, nil

View File

@ -21,12 +21,12 @@ import (
"crypto/x509"
"encoding/base64"
"encoding/pem"
"errors"
"fmt"
"strings"
"github.com/containers/ocicrypt/crypto/pkcs11"
"github.com/pkg/errors"
"golang.org/x/crypto/openpgp"
json "gopkg.in/square/go-jose.v2"
)
@ -36,7 +36,7 @@ func parseJWKPrivateKey(privKey []byte, prefix string) (interface{}, error) {
jwk := json.JSONWebKey{}
err := jwk.UnmarshalJSON(privKey)
if err != nil {
return nil, errors.Wrapf(err, "%s: Could not parse input as JWK", prefix)
return nil, fmt.Errorf("%s: Could not parse input as JWK: %w", prefix, err)
}
if jwk.IsPublic() {
return nil, fmt.Errorf("%s: JWK is not a private key", prefix)
@ -49,7 +49,7 @@ func parseJWKPublicKey(privKey []byte, prefix string) (interface{}, error) {
jwk := json.JSONWebKey{}
err := jwk.UnmarshalJSON(privKey)
if err != nil {
return nil, errors.Wrapf(err, "%s: Could not parse input as JWK", prefix)
return nil, fmt.Errorf("%s: Could not parse input as JWK: %w", prefix, err)
}
if !jwk.IsPublic() {
return nil, fmt.Errorf("%s: JWK is not a public key", prefix)
@ -97,11 +97,11 @@ func ParsePrivateKey(privKey, privKeyPassword []byte, prefix string) (interface{
var der []byte
if x509.IsEncryptedPEMBlock(block) { //nolint:staticcheck // ignore SA1019, which is kept for backward compatibility
if privKeyPassword == nil {
return nil, errors.Errorf("%s: Missing password for encrypted private key", prefix)
return nil, fmt.Errorf("%s: Missing password for encrypted private key", prefix)
}
der, err = x509.DecryptPEMBlock(block, privKeyPassword) //nolint:staticcheck // ignore SA1019, which is kept for backward compatibility
if err != nil {
return nil, errors.Errorf("%s: Wrong password: could not decrypt private key", prefix)
return nil, fmt.Errorf("%s: Wrong password: could not decrypt private key", prefix)
}
} else {
der = block.Bytes
@ -111,7 +111,7 @@ func ParsePrivateKey(privKey, privKeyPassword []byte, prefix string) (interface{
if err != nil {
key, err = x509.ParsePKCS1PrivateKey(der)
if err != nil {
return nil, errors.Wrapf(err, "%s: Could not parse private key", prefix)
return nil, fmt.Errorf("%s: Could not parse private key: %w", prefix, err)
}
}
} else {
@ -145,7 +145,7 @@ func ParsePublicKey(pubKey []byte, prefix string) (interface{}, error) {
if block != nil {
key, err = x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
return nil, errors.Wrapf(err, "%s: Could not parse public key", prefix)
return nil, fmt.Errorf("%s: Could not parse public key: %w", prefix, err)
}
} else {
key, err = parseJWKPublicKey(pubKey, prefix)
@ -179,7 +179,7 @@ func ParseCertificate(certBytes []byte, prefix string) (*x509.Certificate, error
}
x509Cert, err = x509.ParseCertificate(block.Bytes)
if err != nil {
return nil, errors.Wrapf(err, "%s: Could not parse x509 certificate", prefix)
return nil, fmt.Errorf("%s: Could not parse x509 certificate: %w", prefix, err)
}
}
return x509Cert, err

View File

@ -1 +1 @@
1.45.2-dev
1.45.3

View File

@ -16,6 +16,13 @@ This package provides various compression algorithms.
# changelog
* Jan 3rd, 2023 (v1.15.14)
* flate: Improve speed in big stateless blocks https://github.com/klauspost/compress/pull/718
* zstd: Minor speed tweaks by @greatroar in https://github.com/klauspost/compress/pull/716 https://github.com/klauspost/compress/pull/720
* export NoGzipResponseWriter for custom ResponseWriter wrappers by @harshavardhana in https://github.com/klauspost/compress/pull/722
* s2: Add example for indexing and existing stream https://github.com/klauspost/compress/pull/723
* Dec 11, 2022 (v1.15.13)
* zstd: Add [MaxEncodedSize](https://pkg.go.dev/github.com/klauspost/compress@v1.15.13/zstd#Encoder.MaxEncodedSize) to encoder https://github.com/klauspost/compress/pull/691
* zstd: Various tweaks and improvements https://github.com/klauspost/compress/pull/693 https://github.com/klauspost/compress/pull/695 https://github.com/klauspost/compress/pull/696 https://github.com/klauspost/compress/pull/701 https://github.com/klauspost/compress/pull/702 https://github.com/klauspost/compress/pull/703 https://github.com/klauspost/compress/pull/704 https://github.com/klauspost/compress/pull/705 https://github.com/klauspost/compress/pull/706 https://github.com/klauspost/compress/pull/707 https://github.com/klauspost/compress/pull/708

View File

@ -294,7 +294,6 @@ func (d *compressor) findMatch(pos int, prevHead int, lookahead int) (length, of
}
offset = 0
cGain := 0
if d.chain < 100 {
for i := prevHead; tries > 0; tries-- {
if wEnd == win[i+length] {
@ -322,10 +321,14 @@ func (d *compressor) findMatch(pos int, prevHead int, lookahead int) (length, of
return
}
// Minimum gain to accept a match.
cGain := 4
// Some like it higher (CSV), some like it lower (JSON)
const baseCost = 6
const baseCost = 3
// Base is 4 bytes at with an additional cost.
// Matches must be better than this.
for i := prevHead; tries > 0; tries-- {
if wEnd == win[i+length] {
n := matchLen(win[i:i+minMatchLook], wPos)
@ -333,7 +336,7 @@ func (d *compressor) findMatch(pos int, prevHead int, lookahead int) (length, of
// Calculate gain. Estimate
newGain := d.h.bitLengthRaw(wPos[:n]) - int(offsetExtraBits[offsetCode(uint32(pos-i))]) - baseCost - int(lengthExtraBits[lengthCodes[(n-3)&255]])
//fmt.Println(n, "gain:", newGain, "prev:", cGain, "raw:", d.h.bitLengthRaw(wPos[:n]))
//fmt.Println("gain:", newGain, "prev:", cGain, "raw:", d.h.bitLengthRaw(wPos[:n]), "this-len:", n, "prev-len:", length)
if newGain > cGain {
length = n
offset = pos - i
@ -490,27 +493,103 @@ func (d *compressor) deflateLazy() {
}
if prevLength >= minMatchLength && s.length <= prevLength {
// Check for better match at end...
// No better match, but check for better match at end...
//
// checkOff must be >=2 since we otherwise risk checking s.index
// Offset of 2 seems to yield best results.
// Skip forward a number of bytes.
// Offset of 2 seems to yield best results. 3 is sometimes better.
const checkOff = 2
prevIndex := s.index - 1
if prevIndex+prevLength+checkOff < s.maxInsertIndex {
end := lookahead
if lookahead > maxMatchLength {
end = maxMatchLength
}
end += prevIndex
idx := prevIndex + prevLength - (4 - checkOff)
h := hash4(d.window[idx:])
ch2 := int(s.hashHead[h]) - s.hashOffset - prevLength + (4 - checkOff)
if ch2 > minIndex {
length := matchLen(d.window[prevIndex:end], d.window[ch2:])
// It seems like a pure length metric is best.
if length > prevLength {
prevLength = length
prevOffset = prevIndex - ch2
// Check all, except full length
if prevLength < maxMatchLength-checkOff {
prevIndex := s.index - 1
if prevIndex+prevLength < s.maxInsertIndex {
end := lookahead
if lookahead > maxMatchLength+checkOff {
end = maxMatchLength + checkOff
}
end += prevIndex
// Hash at match end.
h := hash4(d.window[prevIndex+prevLength:])
ch2 := int(s.hashHead[h]) - s.hashOffset - prevLength
if prevIndex-ch2 != prevOffset && ch2 > minIndex+checkOff {
length := matchLen(d.window[prevIndex+checkOff:end], d.window[ch2+checkOff:])
// It seems like a pure length metric is best.
if length > prevLength {
prevLength = length
prevOffset = prevIndex - ch2
// Extend back...
for i := checkOff - 1; i >= 0; i-- {
if prevLength >= maxMatchLength || d.window[prevIndex+i] != d.window[ch2+i] {
// Emit tokens we "owe"
for j := 0; j <= i; j++ {
d.tokens.AddLiteral(d.window[prevIndex+j])
if d.tokens.n == maxFlateBlockTokens {
// The block includes the current character
if d.err = d.writeBlock(&d.tokens, s.index, false); d.err != nil {
return
}
d.tokens.Reset()
}
s.index++
if s.index < s.maxInsertIndex {
h := hash4(d.window[s.index:])
ch := s.hashHead[h]
s.chainHead = int(ch)
s.hashPrev[s.index&windowMask] = ch
s.hashHead[h] = uint32(s.index + s.hashOffset)
}
}
break
} else {
prevLength++
}
}
} else if false {
// Check one further ahead.
// Only rarely better, disabled for now.
prevIndex++
h := hash4(d.window[prevIndex+prevLength:])
ch2 := int(s.hashHead[h]) - s.hashOffset - prevLength
if prevIndex-ch2 != prevOffset && ch2 > minIndex+checkOff {
length := matchLen(d.window[prevIndex+checkOff:end], d.window[ch2+checkOff:])
// It seems like a pure length metric is best.
if length > prevLength+checkOff {
prevLength = length
prevOffset = prevIndex - ch2
prevIndex--
// Extend back...
for i := checkOff; i >= 0; i-- {
if prevLength >= maxMatchLength || d.window[prevIndex+i] != d.window[ch2+i-1] {
// Emit tokens we "owe"
for j := 0; j <= i; j++ {
d.tokens.AddLiteral(d.window[prevIndex+j])
if d.tokens.n == maxFlateBlockTokens {
// The block includes the current character
if d.err = d.writeBlock(&d.tokens, s.index, false); d.err != nil {
return
}
d.tokens.Reset()
}
s.index++
if s.index < s.maxInsertIndex {
h := hash4(d.window[s.index:])
ch := s.hashHead[h]
s.chainHead = int(ch)
s.hashPrev[s.index&windowMask] = ch
s.hashHead[h] = uint32(s.index + s.hashOffset)
}
}
break
} else {
prevLength++
}
}
}
}
}
}
}
}

View File

@ -146,54 +146,51 @@ func (s *Scratch) compress(src []byte) error {
c1.encodeZero(tt[src[ip-2]])
ip -= 2
}
src = src[:ip]
// Main compression loop.
switch {
case !s.zeroBits && s.actualTableLog <= 8:
// We can encode 4 symbols without requiring a flush.
// We do not need to check if any output is 0 bits.
for ip >= 4 {
for ; len(src) >= 4; src = src[:len(src)-4] {
s.bw.flush32()
v3, v2, v1, v0 := src[ip-4], src[ip-3], src[ip-2], src[ip-1]
v3, v2, v1, v0 := src[len(src)-4], src[len(src)-3], src[len(src)-2], src[len(src)-1]
c2.encode(tt[v0])
c1.encode(tt[v1])
c2.encode(tt[v2])
c1.encode(tt[v3])
ip -= 4
}
case !s.zeroBits:
// We do not need to check if any output is 0 bits.
for ip >= 4 {
for ; len(src) >= 4; src = src[:len(src)-4] {
s.bw.flush32()
v3, v2, v1, v0 := src[ip-4], src[ip-3], src[ip-2], src[ip-1]
v3, v2, v1, v0 := src[len(src)-4], src[len(src)-3], src[len(src)-2], src[len(src)-1]
c2.encode(tt[v0])
c1.encode(tt[v1])
s.bw.flush32()
c2.encode(tt[v2])
c1.encode(tt[v3])
ip -= 4
}
case s.actualTableLog <= 8:
// We can encode 4 symbols without requiring a flush
for ip >= 4 {
for ; len(src) >= 4; src = src[:len(src)-4] {
s.bw.flush32()
v3, v2, v1, v0 := src[ip-4], src[ip-3], src[ip-2], src[ip-1]
v3, v2, v1, v0 := src[len(src)-4], src[len(src)-3], src[len(src)-2], src[len(src)-1]
c2.encodeZero(tt[v0])
c1.encodeZero(tt[v1])
c2.encodeZero(tt[v2])
c1.encodeZero(tt[v3])
ip -= 4
}
default:
for ip >= 4 {
for ; len(src) >= 4; src = src[:len(src)-4] {
s.bw.flush32()
v3, v2, v1, v0 := src[ip-4], src[ip-3], src[ip-2], src[ip-1]
v3, v2, v1, v0 := src[len(src)-4], src[len(src)-3], src[len(src)-2], src[len(src)-1]
c2.encodeZero(tt[v0])
c1.encodeZero(tt[v1])
s.bw.flush32()
c2.encodeZero(tt[v2])
c1.encodeZero(tt[v3])
ip -= 4
}
}
@ -459,15 +456,17 @@ func (s *Scratch) countSimple(in []byte) (max int) {
for _, v := range in {
s.count[v]++
}
m := uint32(0)
m, symlen := uint32(0), s.symbolLen
for i, v := range s.count[:] {
if v == 0 {
continue
}
if v > m {
m = v
}
if v > 0 {
s.symbolLen = uint16(i) + 1
}
symlen = uint16(i) + 1
}
s.symbolLen = symlen
return int(m)
}

View File

@ -67,7 +67,6 @@ func (b *bitReaderBytes) fillFast() {
// 2 bounds checks.
v := b.in[b.off-4 : b.off]
v = v[:4]
low := (uint32(v[0])) | (uint32(v[1]) << 8) | (uint32(v[2]) << 16) | (uint32(v[3]) << 24)
b.value |= uint64(low) << (b.bitsRead - 32)
b.bitsRead -= 32
@ -88,8 +87,7 @@ func (b *bitReaderBytes) fill() {
return
}
if b.off > 4 {
v := b.in[b.off-4:]
v = v[:4]
v := b.in[b.off-4 : b.off]
low := (uint32(v[0])) | (uint32(v[1]) << 8) | (uint32(v[2]) << 16) | (uint32(v[3]) << 24)
b.value |= uint64(low) << (b.bitsRead - 32)
b.bitsRead -= 32
@ -179,7 +177,6 @@ func (b *bitReaderShifted) fillFast() {
// 2 bounds checks.
v := b.in[b.off-4 : b.off]
v = v[:4]
low := (uint32(v[0])) | (uint32(v[1]) << 8) | (uint32(v[2]) << 16) | (uint32(v[3]) << 24)
b.value |= uint64(low) << ((b.bitsRead - 32) & 63)
b.bitsRead -= 32
@ -200,8 +197,7 @@ func (b *bitReaderShifted) fill() {
return
}
if b.off > 4 {
v := b.in[b.off-4:]
v = v[:4]
v := b.in[b.off-4 : b.off]
low := (uint32(v[0])) | (uint32(v[1]) << 8) | (uint32(v[2]) << 16) | (uint32(v[3]) << 24)
b.value |= uint64(low) << ((b.bitsRead - 32) & 63)
b.bitsRead -= 32

View File

@ -484,34 +484,35 @@ func (s *Scratch) buildCTable() error {
// Different from reference implementation.
huffNode0 := s.nodes[0 : huffNodesLen+1]
for huffNode[nonNullRank].count == 0 {
for huffNode[nonNullRank].count() == 0 {
nonNullRank--
}
lowS := int16(nonNullRank)
nodeRoot := nodeNb + lowS - 1
lowN := nodeNb
huffNode[nodeNb].count = huffNode[lowS].count + huffNode[lowS-1].count
huffNode[lowS].parent, huffNode[lowS-1].parent = uint16(nodeNb), uint16(nodeNb)
huffNode[nodeNb].setCount(huffNode[lowS].count() + huffNode[lowS-1].count())
huffNode[lowS].setParent(nodeNb)
huffNode[lowS-1].setParent(nodeNb)
nodeNb++
lowS -= 2
for n := nodeNb; n <= nodeRoot; n++ {
huffNode[n].count = 1 << 30
huffNode[n].setCount(1 << 30)
}
// fake entry, strong barrier
huffNode0[0].count = 1 << 31
huffNode0[0].setCount(1 << 31)
// create parents
for nodeNb <= nodeRoot {
var n1, n2 int16
if huffNode0[lowS+1].count < huffNode0[lowN+1].count {
if huffNode0[lowS+1].count() < huffNode0[lowN+1].count() {
n1 = lowS
lowS--
} else {
n1 = lowN
lowN++
}
if huffNode0[lowS+1].count < huffNode0[lowN+1].count {
if huffNode0[lowS+1].count() < huffNode0[lowN+1].count() {
n2 = lowS
lowS--
} else {
@ -519,18 +520,19 @@ func (s *Scratch) buildCTable() error {
lowN++
}
huffNode[nodeNb].count = huffNode0[n1+1].count + huffNode0[n2+1].count
huffNode0[n1+1].parent, huffNode0[n2+1].parent = uint16(nodeNb), uint16(nodeNb)
huffNode[nodeNb].setCount(huffNode0[n1+1].count() + huffNode0[n2+1].count())
huffNode0[n1+1].setParent(nodeNb)
huffNode0[n2+1].setParent(nodeNb)
nodeNb++
}
// distribute weights (unlimited tree height)
huffNode[nodeRoot].nbBits = 0
huffNode[nodeRoot].setNbBits(0)
for n := nodeRoot - 1; n >= startNode; n-- {
huffNode[n].nbBits = huffNode[huffNode[n].parent].nbBits + 1
huffNode[n].setNbBits(huffNode[huffNode[n].parent()].nbBits() + 1)
}
for n := uint16(0); n <= nonNullRank; n++ {
huffNode[n].nbBits = huffNode[huffNode[n].parent].nbBits + 1
huffNode[n].setNbBits(huffNode[huffNode[n].parent()].nbBits() + 1)
}
s.actualTableLog = s.setMaxHeight(int(nonNullRank))
maxNbBits := s.actualTableLog
@ -542,7 +544,7 @@ func (s *Scratch) buildCTable() error {
var nbPerRank [tableLogMax + 1]uint16
var valPerRank [16]uint16
for _, v := range huffNode[:nonNullRank+1] {
nbPerRank[v.nbBits]++
nbPerRank[v.nbBits()]++
}
// determine stating value per rank
{
@ -557,7 +559,7 @@ func (s *Scratch) buildCTable() error {
// push nbBits per symbol, symbol order
for _, v := range huffNode[:nonNullRank+1] {
s.cTable[v.symbol].nBits = v.nbBits
s.cTable[v.symbol()].nBits = v.nbBits()
}
// assign value within rank, symbol order
@ -603,12 +605,12 @@ func (s *Scratch) huffSort() {
pos := rank[r].current
rank[r].current++
prev := nodes[(pos-1)&huffNodesMask]
for pos > rank[r].base && c > prev.count {
for pos > rank[r].base && c > prev.count() {
nodes[pos&huffNodesMask] = prev
pos--
prev = nodes[(pos-1)&huffNodesMask]
}
nodes[pos&huffNodesMask] = nodeElt{count: c, symbol: byte(n)}
nodes[pos&huffNodesMask] = makeNodeElt(c, byte(n))
}
}
@ -617,7 +619,7 @@ func (s *Scratch) setMaxHeight(lastNonNull int) uint8 {
huffNode := s.nodes[1 : huffNodesLen+1]
//huffNode = huffNode[: huffNodesLen]
largestBits := huffNode[lastNonNull].nbBits
largestBits := huffNode[lastNonNull].nbBits()
// early exit : no elt > maxNbBits
if largestBits <= maxNbBits {
@ -627,14 +629,14 @@ func (s *Scratch) setMaxHeight(lastNonNull int) uint8 {
baseCost := int(1) << (largestBits - maxNbBits)
n := uint32(lastNonNull)
for huffNode[n].nbBits > maxNbBits {
totalCost += baseCost - (1 << (largestBits - huffNode[n].nbBits))
huffNode[n].nbBits = maxNbBits
for huffNode[n].nbBits() > maxNbBits {
totalCost += baseCost - (1 << (largestBits - huffNode[n].nbBits()))
huffNode[n].setNbBits(maxNbBits)
n--
}
// n stops at huffNode[n].nbBits <= maxNbBits
for huffNode[n].nbBits == maxNbBits {
for huffNode[n].nbBits() == maxNbBits {
n--
}
// n end at index of smallest symbol using < maxNbBits
@ -655,10 +657,10 @@ func (s *Scratch) setMaxHeight(lastNonNull int) uint8 {
{
currentNbBits := maxNbBits
for pos := int(n); pos >= 0; pos-- {
if huffNode[pos].nbBits >= currentNbBits {
if huffNode[pos].nbBits() >= currentNbBits {
continue
}
currentNbBits = huffNode[pos].nbBits // < maxNbBits
currentNbBits = huffNode[pos].nbBits() // < maxNbBits
rankLast[maxNbBits-currentNbBits] = uint32(pos)
}
}
@ -675,8 +677,8 @@ func (s *Scratch) setMaxHeight(lastNonNull int) uint8 {
if lowPos == noSymbol {
break
}
highTotal := huffNode[highPos].count
lowTotal := 2 * huffNode[lowPos].count
highTotal := huffNode[highPos].count()
lowTotal := 2 * huffNode[lowPos].count()
if highTotal <= lowTotal {
break
}
@ -692,13 +694,14 @@ func (s *Scratch) setMaxHeight(lastNonNull int) uint8 {
// this rank is no longer empty
rankLast[nBitsToDecrease-1] = rankLast[nBitsToDecrease]
}
huffNode[rankLast[nBitsToDecrease]].nbBits++
huffNode[rankLast[nBitsToDecrease]].setNbBits(1 +
huffNode[rankLast[nBitsToDecrease]].nbBits())
if rankLast[nBitsToDecrease] == 0 {
/* special case, reached largest symbol */
rankLast[nBitsToDecrease] = noSymbol
} else {
rankLast[nBitsToDecrease]--
if huffNode[rankLast[nBitsToDecrease]].nbBits != maxNbBits-nBitsToDecrease {
if huffNode[rankLast[nBitsToDecrease]].nbBits() != maxNbBits-nBitsToDecrease {
rankLast[nBitsToDecrease] = noSymbol /* this rank is now empty */
}
}
@ -706,15 +709,15 @@ func (s *Scratch) setMaxHeight(lastNonNull int) uint8 {
for totalCost < 0 { /* Sometimes, cost correction overshoot */
if rankLast[1] == noSymbol { /* special case : no rank 1 symbol (using maxNbBits-1); let's create one from largest rank 0 (using maxNbBits) */
for huffNode[n].nbBits == maxNbBits {
for huffNode[n].nbBits() == maxNbBits {
n--
}
huffNode[n+1].nbBits--
huffNode[n+1].setNbBits(huffNode[n+1].nbBits() - 1)
rankLast[1] = n + 1
totalCost++
continue
}
huffNode[rankLast[1]+1].nbBits--
huffNode[rankLast[1]+1].setNbBits(huffNode[rankLast[1]+1].nbBits() - 1)
rankLast[1]++
totalCost++
}
@ -722,9 +725,26 @@ func (s *Scratch) setMaxHeight(lastNonNull int) uint8 {
return maxNbBits
}
type nodeElt struct {
count uint32
parent uint16
symbol byte
nbBits uint8
// A nodeElt is the fields
//
// count uint32
// parent uint16
// symbol byte
// nbBits uint8
//
// in some order, all squashed into an integer so that the compiler
// always loads and stores entire nodeElts instead of separate fields.
type nodeElt uint64
func makeNodeElt(count uint32, symbol byte) nodeElt {
return nodeElt(count) | nodeElt(symbol)<<48
}
func (e *nodeElt) count() uint32 { return uint32(*e) }
func (e *nodeElt) parent() uint16 { return uint16(*e >> 32) }
func (e *nodeElt) symbol() byte { return byte(*e >> 48) }
func (e *nodeElt) nbBits() uint8 { return uint8(*e >> 56) }
func (e *nodeElt) setCount(c uint32) { *e = (*e)&0xffffffff00000000 | nodeElt(c) }
func (e *nodeElt) setParent(p int16) { *e = (*e)&0xffff0000ffffffff | nodeElt(uint16(p))<<32 }
func (e *nodeElt) setNbBits(n uint8) { *e = (*e)&0x00ffffffffffffff | nodeElt(n)<<56 }

View File

@ -4,360 +4,349 @@
// func decompress4x_main_loop_amd64(ctx *decompress4xContext)
TEXT ·decompress4x_main_loop_amd64(SB), $0-8
XORQ DX, DX
// Preload values
MOVQ ctx+0(FP), AX
MOVBQZX 8(AX), DI
MOVQ 16(AX), SI
MOVQ 48(AX), BX
MOVQ 24(AX), R9
MOVQ 32(AX), R10
MOVQ (AX), R11
MOVQ 16(AX), BX
MOVQ 48(AX), SI
MOVQ 24(AX), R8
MOVQ 32(AX), R9
MOVQ (AX), R10
// Main loop
main_loop:
MOVQ SI, R8
CMPQ R8, BX
XORL DX, DX
CMPQ BX, SI
SETGE DL
// br0.fillFast32()
MOVQ 32(R11), R12
MOVBQZX 40(R11), R13
CMPQ R13, $0x20
MOVQ 32(R10), R11
MOVBQZX 40(R10), R12
CMPQ R12, $0x20
JBE skip_fill0
MOVQ 24(R11), AX
SUBQ $0x20, R13
MOVQ 24(R10), AX
SUBQ $0x20, R12
SUBQ $0x04, AX
MOVQ (R11), R14
MOVQ (R10), R13
// b.value |= uint64(low) << (b.bitsRead & 63)
MOVL (AX)(R14*1), R14
MOVQ R13, CX
SHLQ CL, R14
MOVQ AX, 24(R11)
ORQ R14, R12
MOVL (AX)(R13*1), R13
MOVQ R12, CX
SHLQ CL, R13
MOVQ AX, 24(R10)
ORQ R13, R11
// exhausted = exhausted || (br0.off < 4)
CMPQ AX, $0x04
SETLT AL
ORB AL, DL
// exhausted += (br0.off < 4)
CMPQ AX, $0x04
ADCB $+0, DL
skip_fill0:
// val0 := br0.peekTopBits(peekBits)
MOVQ R12, R14
MOVQ R11, R13
MOVQ DI, CX
SHRQ CL, R14
SHRQ CL, R13
// v0 := table[val0&mask]
MOVW (R10)(R14*2), CX
MOVW (R9)(R13*2), CX
// br0.advance(uint8(v0.entry)
MOVB CH, AL
SHLQ CL, R12
ADDB CL, R13
SHLQ CL, R11
ADDB CL, R12
// val1 := br0.peekTopBits(peekBits)
MOVQ DI, CX
MOVQ R12, R14
SHRQ CL, R14
MOVQ R11, R13
SHRQ CL, R13
// v1 := table[val1&mask]
MOVW (R10)(R14*2), CX
MOVW (R9)(R13*2), CX
// br0.advance(uint8(v1.entry))
MOVB CH, AH
SHLQ CL, R12
ADDB CL, R13
SHLQ CL, R11
ADDB CL, R12
// these two writes get coalesced
// out[id * dstEvery + 0] = uint8(v0.entry >> 8)
// out[id * dstEvery + 1] = uint8(v1.entry >> 8)
MOVW AX, (R8)
MOVW AX, (BX)
// update the bitreader structure
MOVQ R12, 32(R11)
MOVB R13, 40(R11)
ADDQ R9, R8
MOVQ R11, 32(R10)
MOVB R12, 40(R10)
// br1.fillFast32()
MOVQ 80(R11), R12
MOVBQZX 88(R11), R13
CMPQ R13, $0x20
MOVQ 80(R10), R11
MOVBQZX 88(R10), R12
CMPQ R12, $0x20
JBE skip_fill1
MOVQ 72(R11), AX
SUBQ $0x20, R13
MOVQ 72(R10), AX
SUBQ $0x20, R12
SUBQ $0x04, AX
MOVQ 48(R11), R14
MOVQ 48(R10), R13
// b.value |= uint64(low) << (b.bitsRead & 63)
MOVL (AX)(R14*1), R14
MOVQ R13, CX
SHLQ CL, R14
MOVQ AX, 72(R11)
ORQ R14, R12
MOVL (AX)(R13*1), R13
MOVQ R12, CX
SHLQ CL, R13
MOVQ AX, 72(R10)
ORQ R13, R11
// exhausted = exhausted || (br1.off < 4)
CMPQ AX, $0x04
SETLT AL
ORB AL, DL
// exhausted += (br1.off < 4)
CMPQ AX, $0x04
ADCB $+0, DL
skip_fill1:
// val0 := br1.peekTopBits(peekBits)
MOVQ R12, R14
MOVQ R11, R13
MOVQ DI, CX
SHRQ CL, R14
SHRQ CL, R13
// v0 := table[val0&mask]
MOVW (R10)(R14*2), CX
MOVW (R9)(R13*2), CX
// br1.advance(uint8(v0.entry)
MOVB CH, AL
SHLQ CL, R12
ADDB CL, R13
SHLQ CL, R11
ADDB CL, R12
// val1 := br1.peekTopBits(peekBits)
MOVQ DI, CX
MOVQ R12, R14
SHRQ CL, R14
MOVQ R11, R13
SHRQ CL, R13
// v1 := table[val1&mask]
MOVW (R10)(R14*2), CX
MOVW (R9)(R13*2), CX
// br1.advance(uint8(v1.entry))
MOVB CH, AH
SHLQ CL, R12
ADDB CL, R13
SHLQ CL, R11
ADDB CL, R12
// these two writes get coalesced
// out[id * dstEvery + 0] = uint8(v0.entry >> 8)
// out[id * dstEvery + 1] = uint8(v1.entry >> 8)
MOVW AX, (R8)
MOVW AX, (BX)(R8*1)
// update the bitreader structure
MOVQ R12, 80(R11)
MOVB R13, 88(R11)
ADDQ R9, R8
MOVQ R11, 80(R10)
MOVB R12, 88(R10)
// br2.fillFast32()
MOVQ 128(R11), R12
MOVBQZX 136(R11), R13
CMPQ R13, $0x20
MOVQ 128(R10), R11
MOVBQZX 136(R10), R12
CMPQ R12, $0x20
JBE skip_fill2
MOVQ 120(R11), AX
SUBQ $0x20, R13
MOVQ 120(R10), AX
SUBQ $0x20, R12
SUBQ $0x04, AX
MOVQ 96(R11), R14
MOVQ 96(R10), R13
// b.value |= uint64(low) << (b.bitsRead & 63)
MOVL (AX)(R14*1), R14
MOVQ R13, CX
SHLQ CL, R14
MOVQ AX, 120(R11)
ORQ R14, R12
MOVL (AX)(R13*1), R13
MOVQ R12, CX
SHLQ CL, R13
MOVQ AX, 120(R10)
ORQ R13, R11
// exhausted = exhausted || (br2.off < 4)
CMPQ AX, $0x04
SETLT AL
ORB AL, DL
// exhausted += (br2.off < 4)
CMPQ AX, $0x04
ADCB $+0, DL
skip_fill2:
// val0 := br2.peekTopBits(peekBits)
MOVQ R12, R14
MOVQ R11, R13
MOVQ DI, CX
SHRQ CL, R14
SHRQ CL, R13
// v0 := table[val0&mask]
MOVW (R10)(R14*2), CX
MOVW (R9)(R13*2), CX
// br2.advance(uint8(v0.entry)
MOVB CH, AL
SHLQ CL, R12
ADDB CL, R13
SHLQ CL, R11
ADDB CL, R12
// val1 := br2.peekTopBits(peekBits)
MOVQ DI, CX
MOVQ R12, R14
SHRQ CL, R14
MOVQ R11, R13
SHRQ CL, R13
// v1 := table[val1&mask]
MOVW (R10)(R14*2), CX
MOVW (R9)(R13*2), CX
// br2.advance(uint8(v1.entry))
MOVB CH, AH
SHLQ CL, R12
ADDB CL, R13
SHLQ CL, R11
ADDB CL, R12
// these two writes get coalesced
// out[id * dstEvery + 0] = uint8(v0.entry >> 8)
// out[id * dstEvery + 1] = uint8(v1.entry >> 8)
MOVW AX, (R8)
MOVW AX, (BX)(R8*2)
// update the bitreader structure
MOVQ R12, 128(R11)
MOVB R13, 136(R11)
ADDQ R9, R8
MOVQ R11, 128(R10)
MOVB R12, 136(R10)
// br3.fillFast32()
MOVQ 176(R11), R12
MOVBQZX 184(R11), R13
CMPQ R13, $0x20
MOVQ 176(R10), R11
MOVBQZX 184(R10), R12
CMPQ R12, $0x20
JBE skip_fill3
MOVQ 168(R11), AX
SUBQ $0x20, R13
MOVQ 168(R10), AX
SUBQ $0x20, R12
SUBQ $0x04, AX
MOVQ 144(R11), R14
MOVQ 144(R10), R13
// b.value |= uint64(low) << (b.bitsRead & 63)
MOVL (AX)(R14*1), R14
MOVQ R13, CX
SHLQ CL, R14
MOVQ AX, 168(R11)
ORQ R14, R12
MOVL (AX)(R13*1), R13
MOVQ R12, CX
SHLQ CL, R13
MOVQ AX, 168(R10)
ORQ R13, R11
// exhausted = exhausted || (br3.off < 4)
CMPQ AX, $0x04
SETLT AL
ORB AL, DL
// exhausted += (br3.off < 4)
CMPQ AX, $0x04
ADCB $+0, DL
skip_fill3:
// val0 := br3.peekTopBits(peekBits)
MOVQ R12, R14
MOVQ R11, R13
MOVQ DI, CX
SHRQ CL, R14
SHRQ CL, R13
// v0 := table[val0&mask]
MOVW (R10)(R14*2), CX
MOVW (R9)(R13*2), CX
// br3.advance(uint8(v0.entry)
MOVB CH, AL
SHLQ CL, R12
ADDB CL, R13
SHLQ CL, R11
ADDB CL, R12
// val1 := br3.peekTopBits(peekBits)
MOVQ DI, CX
MOVQ R12, R14
SHRQ CL, R14
MOVQ R11, R13
SHRQ CL, R13
// v1 := table[val1&mask]
MOVW (R10)(R14*2), CX
MOVW (R9)(R13*2), CX
// br3.advance(uint8(v1.entry))
MOVB CH, AH
SHLQ CL, R12
ADDB CL, R13
SHLQ CL, R11
ADDB CL, R12
// these two writes get coalesced
// out[id * dstEvery + 0] = uint8(v0.entry >> 8)
// out[id * dstEvery + 1] = uint8(v1.entry >> 8)
MOVW AX, (R8)
LEAQ (R8)(R8*2), CX
MOVW AX, (BX)(CX*1)
// update the bitreader structure
MOVQ R12, 176(R11)
MOVB R13, 184(R11)
ADDQ $0x02, SI
MOVQ R11, 176(R10)
MOVB R12, 184(R10)
ADDQ $0x02, BX
TESTB DL, DL
JZ main_loop
MOVQ ctx+0(FP), AX
SUBQ 16(AX), SI
SHLQ $0x02, SI
MOVQ SI, 40(AX)
SUBQ 16(AX), BX
SHLQ $0x02, BX
MOVQ BX, 40(AX)
RET
// func decompress4x_8b_main_loop_amd64(ctx *decompress4xContext)
TEXT ·decompress4x_8b_main_loop_amd64(SB), $0-8
XORQ DX, DX
// Preload values
MOVQ ctx+0(FP), CX
MOVBQZX 8(CX), DI
MOVQ 16(CX), BX
MOVQ 48(CX), SI
MOVQ 24(CX), R9
MOVQ 32(CX), R10
MOVQ (CX), R11
MOVQ 24(CX), R8
MOVQ 32(CX), R9
MOVQ (CX), R10
// Main loop
main_loop:
MOVQ BX, R8
CMPQ R8, SI
XORL DX, DX
CMPQ BX, SI
SETGE DL
// br0.fillFast32()
MOVQ 32(R11), R12
MOVBQZX 40(R11), R13
CMPQ R13, $0x20
MOVQ 32(R10), R11
MOVBQZX 40(R10), R12
CMPQ R12, $0x20
JBE skip_fill0
MOVQ 24(R11), R14
SUBQ $0x20, R13
SUBQ $0x04, R14
MOVQ (R11), R15
MOVQ 24(R10), R13
SUBQ $0x20, R12
SUBQ $0x04, R13
MOVQ (R10), R14
// b.value |= uint64(low) << (b.bitsRead & 63)
MOVL (R14)(R15*1), R15
MOVQ R13, CX
SHLQ CL, R15
MOVQ R14, 24(R11)
ORQ R15, R12
MOVL (R13)(R14*1), R14
MOVQ R12, CX
SHLQ CL, R14
MOVQ R13, 24(R10)
ORQ R14, R11
// exhausted = exhausted || (br0.off < 4)
CMPQ R14, $0x04
SETLT AL
ORB AL, DL
// exhausted += (br0.off < 4)
CMPQ R13, $0x04
ADCB $+0, DL
skip_fill0:
// val0 := br0.peekTopBits(peekBits)
MOVQ R12, R14
MOVQ R11, R13
MOVQ DI, CX
SHRQ CL, R14
SHRQ CL, R13
// v0 := table[val0&mask]
MOVW (R10)(R14*2), CX
MOVW (R9)(R13*2), CX
// br0.advance(uint8(v0.entry)
MOVB CH, AL
SHLQ CL, R12
ADDB CL, R13
SHLQ CL, R11
ADDB CL, R12
// val1 := br0.peekTopBits(peekBits)
MOVQ R12, R14
MOVQ R11, R13
MOVQ DI, CX
SHRQ CL, R14
SHRQ CL, R13
// v1 := table[val0&mask]
MOVW (R10)(R14*2), CX
MOVW (R9)(R13*2), CX
// br0.advance(uint8(v1.entry)
MOVB CH, AH
SHLQ CL, R12
ADDB CL, R13
SHLQ CL, R11
ADDB CL, R12
BSWAPL AX
// val2 := br0.peekTopBits(peekBits)
MOVQ R12, R14
MOVQ R11, R13
MOVQ DI, CX
SHRQ CL, R14
SHRQ CL, R13
// v2 := table[val0&mask]
MOVW (R10)(R14*2), CX
MOVW (R9)(R13*2), CX
// br0.advance(uint8(v2.entry)
MOVB CH, AH
SHLQ CL, R12
ADDB CL, R13
SHLQ CL, R11
ADDB CL, R12
// val3 := br0.peekTopBits(peekBits)
MOVQ R12, R14
MOVQ R11, R13
MOVQ DI, CX
SHRQ CL, R14
SHRQ CL, R13
// v3 := table[val0&mask]
MOVW (R10)(R14*2), CX
MOVW (R9)(R13*2), CX
// br0.advance(uint8(v3.entry)
MOVB CH, AL
SHLQ CL, R12
ADDB CL, R13
SHLQ CL, R11
ADDB CL, R12
BSWAPL AX
// these four writes get coalesced
@ -365,88 +354,86 @@ skip_fill0:
// out[id * dstEvery + 1] = uint8(v1.entry >> 8)
// out[id * dstEvery + 3] = uint8(v2.entry >> 8)
// out[id * dstEvery + 4] = uint8(v3.entry >> 8)
MOVL AX, (R8)
MOVL AX, (BX)
// update the bitreader structure
MOVQ R12, 32(R11)
MOVB R13, 40(R11)
ADDQ R9, R8
MOVQ R11, 32(R10)
MOVB R12, 40(R10)
// br1.fillFast32()
MOVQ 80(R11), R12
MOVBQZX 88(R11), R13
CMPQ R13, $0x20
MOVQ 80(R10), R11
MOVBQZX 88(R10), R12
CMPQ R12, $0x20
JBE skip_fill1
MOVQ 72(R11), R14
SUBQ $0x20, R13
SUBQ $0x04, R14
MOVQ 48(R11), R15
MOVQ 72(R10), R13
SUBQ $0x20, R12
SUBQ $0x04, R13
MOVQ 48(R10), R14
// b.value |= uint64(low) << (b.bitsRead & 63)
MOVL (R14)(R15*1), R15
MOVQ R13, CX
SHLQ CL, R15
MOVQ R14, 72(R11)
ORQ R15, R12
MOVL (R13)(R14*1), R14
MOVQ R12, CX
SHLQ CL, R14
MOVQ R13, 72(R10)
ORQ R14, R11
// exhausted = exhausted || (br1.off < 4)
CMPQ R14, $0x04
SETLT AL
ORB AL, DL
// exhausted += (br1.off < 4)
CMPQ R13, $0x04
ADCB $+0, DL
skip_fill1:
// val0 := br1.peekTopBits(peekBits)
MOVQ R12, R14
MOVQ R11, R13
MOVQ DI, CX
SHRQ CL, R14
SHRQ CL, R13
// v0 := table[val0&mask]
MOVW (R10)(R14*2), CX
MOVW (R9)(R13*2), CX
// br1.advance(uint8(v0.entry)
MOVB CH, AL
SHLQ CL, R12
ADDB CL, R13
SHLQ CL, R11
ADDB CL, R12
// val1 := br1.peekTopBits(peekBits)
MOVQ R12, R14
MOVQ R11, R13
MOVQ DI, CX
SHRQ CL, R14
SHRQ CL, R13
// v1 := table[val0&mask]
MOVW (R10)(R14*2), CX
MOVW (R9)(R13*2), CX
// br1.advance(uint8(v1.entry)
MOVB CH, AH
SHLQ CL, R12
ADDB CL, R13
SHLQ CL, R11
ADDB CL, R12
BSWAPL AX
// val2 := br1.peekTopBits(peekBits)
MOVQ R12, R14
MOVQ R11, R13
MOVQ DI, CX
SHRQ CL, R14
SHRQ CL, R13
// v2 := table[val0&mask]
MOVW (R10)(R14*2), CX
MOVW (R9)(R13*2), CX
// br1.advance(uint8(v2.entry)
MOVB CH, AH
SHLQ CL, R12
ADDB CL, R13
SHLQ CL, R11
ADDB CL, R12
// val3 := br1.peekTopBits(peekBits)
MOVQ R12, R14
MOVQ R11, R13
MOVQ DI, CX
SHRQ CL, R14
SHRQ CL, R13
// v3 := table[val0&mask]
MOVW (R10)(R14*2), CX
MOVW (R9)(R13*2), CX
// br1.advance(uint8(v3.entry)
MOVB CH, AL
SHLQ CL, R12
ADDB CL, R13
SHLQ CL, R11
ADDB CL, R12
BSWAPL AX
// these four writes get coalesced
@ -454,88 +441,86 @@ skip_fill1:
// out[id * dstEvery + 1] = uint8(v1.entry >> 8)
// out[id * dstEvery + 3] = uint8(v2.entry >> 8)
// out[id * dstEvery + 4] = uint8(v3.entry >> 8)
MOVL AX, (R8)
MOVL AX, (BX)(R8*1)
// update the bitreader structure
MOVQ R12, 80(R11)
MOVB R13, 88(R11)
ADDQ R9, R8
MOVQ R11, 80(R10)
MOVB R12, 88(R10)
// br2.fillFast32()
MOVQ 128(R11), R12
MOVBQZX 136(R11), R13
CMPQ R13, $0x20
MOVQ 128(R10), R11
MOVBQZX 136(R10), R12
CMPQ R12, $0x20
JBE skip_fill2
MOVQ 120(R11), R14
SUBQ $0x20, R13
SUBQ $0x04, R14
MOVQ 96(R11), R15
MOVQ 120(R10), R13
SUBQ $0x20, R12
SUBQ $0x04, R13
MOVQ 96(R10), R14
// b.value |= uint64(low) << (b.bitsRead & 63)
MOVL (R14)(R15*1), R15
MOVQ R13, CX
SHLQ CL, R15
MOVQ R14, 120(R11)
ORQ R15, R12
MOVL (R13)(R14*1), R14
MOVQ R12, CX
SHLQ CL, R14
MOVQ R13, 120(R10)
ORQ R14, R11
// exhausted = exhausted || (br2.off < 4)
CMPQ R14, $0x04
SETLT AL
ORB AL, DL
// exhausted += (br2.off < 4)
CMPQ R13, $0x04
ADCB $+0, DL
skip_fill2:
// val0 := br2.peekTopBits(peekBits)
MOVQ R12, R14
MOVQ R11, R13
MOVQ DI, CX
SHRQ CL, R14
SHRQ CL, R13
// v0 := table[val0&mask]
MOVW (R10)(R14*2), CX
MOVW (R9)(R13*2), CX
// br2.advance(uint8(v0.entry)
MOVB CH, AL
SHLQ CL, R12
ADDB CL, R13
SHLQ CL, R11
ADDB CL, R12
// val1 := br2.peekTopBits(peekBits)
MOVQ R12, R14
MOVQ R11, R13
MOVQ DI, CX
SHRQ CL, R14
SHRQ CL, R13
// v1 := table[val0&mask]
MOVW (R10)(R14*2), CX
MOVW (R9)(R13*2), CX
// br2.advance(uint8(v1.entry)
MOVB CH, AH
SHLQ CL, R12
ADDB CL, R13
SHLQ CL, R11
ADDB CL, R12
BSWAPL AX
// val2 := br2.peekTopBits(peekBits)
MOVQ R12, R14
MOVQ R11, R13
MOVQ DI, CX
SHRQ CL, R14
SHRQ CL, R13
// v2 := table[val0&mask]
MOVW (R10)(R14*2), CX
MOVW (R9)(R13*2), CX
// br2.advance(uint8(v2.entry)
MOVB CH, AH
SHLQ CL, R12
ADDB CL, R13
SHLQ CL, R11
ADDB CL, R12
// val3 := br2.peekTopBits(peekBits)
MOVQ R12, R14
MOVQ R11, R13
MOVQ DI, CX
SHRQ CL, R14
SHRQ CL, R13
// v3 := table[val0&mask]
MOVW (R10)(R14*2), CX
MOVW (R9)(R13*2), CX
// br2.advance(uint8(v3.entry)
MOVB CH, AL
SHLQ CL, R12
ADDB CL, R13
SHLQ CL, R11
ADDB CL, R12
BSWAPL AX
// these four writes get coalesced
@ -543,88 +528,86 @@ skip_fill2:
// out[id * dstEvery + 1] = uint8(v1.entry >> 8)
// out[id * dstEvery + 3] = uint8(v2.entry >> 8)
// out[id * dstEvery + 4] = uint8(v3.entry >> 8)
MOVL AX, (R8)
MOVL AX, (BX)(R8*2)
// update the bitreader structure
MOVQ R12, 128(R11)
MOVB R13, 136(R11)
ADDQ R9, R8
MOVQ R11, 128(R10)
MOVB R12, 136(R10)
// br3.fillFast32()
MOVQ 176(R11), R12
MOVBQZX 184(R11), R13
CMPQ R13, $0x20
MOVQ 176(R10), R11
MOVBQZX 184(R10), R12
CMPQ R12, $0x20
JBE skip_fill3
MOVQ 168(R11), R14
SUBQ $0x20, R13
SUBQ $0x04, R14
MOVQ 144(R11), R15
MOVQ 168(R10), R13
SUBQ $0x20, R12
SUBQ $0x04, R13
MOVQ 144(R10), R14
// b.value |= uint64(low) << (b.bitsRead & 63)
MOVL (R14)(R15*1), R15
MOVQ R13, CX
SHLQ CL, R15
MOVQ R14, 168(R11)
ORQ R15, R12
MOVL (R13)(R14*1), R14
MOVQ R12, CX
SHLQ CL, R14
MOVQ R13, 168(R10)
ORQ R14, R11
// exhausted = exhausted || (br3.off < 4)
CMPQ R14, $0x04
SETLT AL
ORB AL, DL
// exhausted += (br3.off < 4)
CMPQ R13, $0x04
ADCB $+0, DL
skip_fill3:
// val0 := br3.peekTopBits(peekBits)
MOVQ R12, R14
MOVQ R11, R13
MOVQ DI, CX
SHRQ CL, R14
SHRQ CL, R13
// v0 := table[val0&mask]
MOVW (R10)(R14*2), CX
MOVW (R9)(R13*2), CX
// br3.advance(uint8(v0.entry)
MOVB CH, AL
SHLQ CL, R12
ADDB CL, R13
SHLQ CL, R11
ADDB CL, R12
// val1 := br3.peekTopBits(peekBits)
MOVQ R12, R14
MOVQ R11, R13
MOVQ DI, CX
SHRQ CL, R14
SHRQ CL, R13
// v1 := table[val0&mask]
MOVW (R10)(R14*2), CX
MOVW (R9)(R13*2), CX
// br3.advance(uint8(v1.entry)
MOVB CH, AH
SHLQ CL, R12
ADDB CL, R13
SHLQ CL, R11
ADDB CL, R12
BSWAPL AX
// val2 := br3.peekTopBits(peekBits)
MOVQ R12, R14
MOVQ R11, R13
MOVQ DI, CX
SHRQ CL, R14
SHRQ CL, R13
// v2 := table[val0&mask]
MOVW (R10)(R14*2), CX
MOVW (R9)(R13*2), CX
// br3.advance(uint8(v2.entry)
MOVB CH, AH
SHLQ CL, R12
ADDB CL, R13
SHLQ CL, R11
ADDB CL, R12
// val3 := br3.peekTopBits(peekBits)
MOVQ R12, R14
MOVQ R11, R13
MOVQ DI, CX
SHRQ CL, R14
SHRQ CL, R13
// v3 := table[val0&mask]
MOVW (R10)(R14*2), CX
MOVW (R9)(R13*2), CX
// br3.advance(uint8(v3.entry)
MOVB CH, AL
SHLQ CL, R12
ADDB CL, R13
SHLQ CL, R11
ADDB CL, R12
BSWAPL AX
// these four writes get coalesced
@ -632,11 +615,12 @@ skip_fill3:
// out[id * dstEvery + 1] = uint8(v1.entry >> 8)
// out[id * dstEvery + 3] = uint8(v2.entry >> 8)
// out[id * dstEvery + 4] = uint8(v3.entry >> 8)
MOVL AX, (R8)
LEAQ (R8)(R8*2), CX
MOVL AX, (BX)(CX*1)
// update the bitreader structure
MOVQ R12, 176(R11)
MOVB R13, 184(R11)
MOVQ R11, 176(R10)
MOVB R12, 184(R10)
ADDQ $0x04, BX
TESTB DL, DL
JZ main_loop
@ -652,7 +636,7 @@ TEXT ·decompress1x_main_loop_amd64(SB), $0-8
MOVQ 16(CX), DX
MOVQ 24(CX), BX
CMPQ BX, $0x04
JB error_max_decoded_size_exeeded
JB error_max_decoded_size_exceeded
LEAQ (DX)(BX*1), BX
MOVQ (CX), SI
MOVQ (SI), R8
@ -667,7 +651,7 @@ main_loop:
// Check if we have room for 4 bytes in the output buffer
LEAQ 4(DX), CX
CMPQ CX, BX
JGE error_max_decoded_size_exeeded
JGE error_max_decoded_size_exceeded
// Decode 4 values
CMPQ R11, $0x20
@ -744,7 +728,7 @@ loop_condition:
RET
// Report error
error_max_decoded_size_exeeded:
error_max_decoded_size_exceeded:
MOVQ ctx+0(FP), AX
MOVQ $-1, CX
MOVQ CX, 40(AX)
@ -757,7 +741,7 @@ TEXT ·decompress1x_main_loop_bmi2(SB), $0-8
MOVQ 16(CX), DX
MOVQ 24(CX), BX
CMPQ BX, $0x04
JB error_max_decoded_size_exeeded
JB error_max_decoded_size_exceeded
LEAQ (DX)(BX*1), BX
MOVQ (CX), SI
MOVQ (SI), R8
@ -772,7 +756,7 @@ main_loop:
// Check if we have room for 4 bytes in the output buffer
LEAQ 4(DX), CX
CMPQ CX, BX
JGE error_max_decoded_size_exeeded
JGE error_max_decoded_size_exceeded
// Decode 4 values
CMPQ R11, $0x20
@ -839,7 +823,7 @@ loop_condition:
RET
// Report error
error_max_decoded_size_exeeded:
error_max_decoded_size_exceeded:
MOVQ ctx+0(FP), AX
MOVQ $-1, CX
MOVQ CX, 40(AX)

View File

@ -192,16 +192,14 @@ func (b *blockDec) reset(br byteBuffer, windowSize uint64) error {
}
// Read block data.
if cap(b.dataStorage) < cSize {
if _, ok := br.(*byteBuf); !ok && cap(b.dataStorage) < cSize {
// byteBuf doesn't need a destination buffer.
if b.lowMem || cSize > maxCompressedBlockSize {
b.dataStorage = make([]byte, 0, cSize+compressedBlockOverAlloc)
} else {
b.dataStorage = make([]byte, 0, maxCompressedBlockSizeAlloc)
}
}
if cap(b.dst) <= maxSize {
b.dst = make([]byte, 0, maxSize+1)
}
b.data, err = br.readBig(cSize, b.dataStorage)
if err != nil {
if debugDecoder {
@ -210,6 +208,9 @@ func (b *blockDec) reset(br byteBuffer, windowSize uint64) error {
}
return err
}
if cap(b.dst) <= maxSize {
b.dst = make([]byte, 0, maxSize+1)
}
return nil
}

View File

@ -40,8 +40,7 @@ type Decoder struct {
frame *frameDec
// Custom dictionaries.
// Always uses copies.
dicts map[uint32]dict
dicts map[uint32]*dict
// streamWg is the waitgroup for all streams
streamWg sync.WaitGroup
@ -103,7 +102,7 @@ func NewReader(r io.Reader, opts ...DOption) (*Decoder, error) {
}
// Transfer option dicts.
d.dicts = make(map[uint32]dict, len(d.o.dicts))
d.dicts = make(map[uint32]*dict, len(d.o.dicts))
for _, dc := range d.o.dicts {
d.dicts[dc.id] = dc
}
@ -341,15 +340,8 @@ func (d *Decoder) DecodeAll(input, dst []byte) ([]byte, error) {
}
return dst, err
}
if frame.DictionaryID != nil {
dict, ok := d.dicts[*frame.DictionaryID]
if !ok {
return nil, ErrUnknownDictionary
}
if debugDecoder {
println("setting dict", frame.DictionaryID)
}
frame.history.setDict(&dict)
if err = d.setDict(frame); err != nil {
return nil, err
}
if frame.WindowSize > d.o.maxWindowSize {
if debugDecoder {
@ -495,18 +487,12 @@ func (d *Decoder) nextBlockSync() (ok bool) {
if !d.syncStream.inFrame {
d.frame.history.reset()
d.current.err = d.frame.reset(&d.syncStream.br)
if d.current.err == nil {
d.current.err = d.setDict(d.frame)
}
if d.current.err != nil {
return false
}
if d.frame.DictionaryID != nil {
dict, ok := d.dicts[*d.frame.DictionaryID]
if !ok {
d.current.err = ErrUnknownDictionary
return false
} else {
d.frame.history.setDict(&dict)
}
}
if d.frame.WindowSize > d.o.maxDecodedSize || d.frame.WindowSize > d.o.maxWindowSize {
d.current.err = ErrDecoderSizeExceeded
return false
@ -865,13 +851,8 @@ decodeStream:
if debugDecoder && err != nil {
println("Frame decoder returned", err)
}
if err == nil && frame.DictionaryID != nil {
dict, ok := d.dicts[*frame.DictionaryID]
if !ok {
err = ErrUnknownDictionary
} else {
frame.history.setDict(&dict)
}
if err == nil {
err = d.setDict(frame)
}
if err == nil && d.frame.WindowSize > d.o.maxWindowSize {
if debugDecoder {
@ -953,3 +934,20 @@ decodeStream:
hist.reset()
d.frame.history.b = frameHistCache
}
func (d *Decoder) setDict(frame *frameDec) (err error) {
dict, ok := d.dicts[frame.DictionaryID]
if ok {
if debugDecoder {
println("setting dict", frame.DictionaryID)
}
frame.history.setDict(dict)
} else if frame.DictionaryID != 0 {
// A zero or missing dictionary id is ambiguous:
// either dictionary zero, or no dictionary. In particular,
// zstd --patch-from uses this id for the source file,
// so only return an error if the dictionary id is not zero.
err = ErrUnknownDictionary
}
return err
}

View File

@ -6,6 +6,8 @@ package zstd
import (
"errors"
"fmt"
"math/bits"
"runtime"
)
@ -18,7 +20,7 @@ type decoderOptions struct {
concurrent int
maxDecodedSize uint64
maxWindowSize uint64
dicts []dict
dicts []*dict
ignoreChecksum bool
limitToCap bool
decodeBufsBelow int
@ -85,7 +87,13 @@ func WithDecoderMaxMemory(n uint64) DOption {
}
// WithDecoderDicts allows to register one or more dictionaries for the decoder.
// If several dictionaries with the same ID is provided the last one will be used.
//
// Each slice in dict must be in the [dictionary format] produced by
// "zstd --train" from the Zstandard reference implementation.
//
// If several dictionaries with the same ID are provided, the last one will be used.
//
// [dictionary format]: https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#dictionary-format
func WithDecoderDicts(dicts ...[]byte) DOption {
return func(o *decoderOptions) error {
for _, b := range dicts {
@ -93,12 +101,24 @@ func WithDecoderDicts(dicts ...[]byte) DOption {
if err != nil {
return err
}
o.dicts = append(o.dicts, *d)
o.dicts = append(o.dicts, d)
}
return nil
}
}
// WithEncoderDictRaw registers a dictionary that may be used by the decoder.
// The slice content can be arbitrary data.
func WithDecoderDictRaw(id uint32, content []byte) DOption {
return func(o *decoderOptions) error {
if bits.UintSize > 32 && uint(len(content)) > dictMaxLength {
return fmt.Errorf("dictionary of size %d > 2GiB too large", len(content))
}
o.dicts = append(o.dicts, &dict{id: id, content: content, offsets: [3]int{1, 4, 8}})
return nil
}
}
// WithDecoderMaxWindow allows to set a maximum window size for decodes.
// This allows rejecting packets that will cause big memory usage.
// The Decoder will likely allocate more memory based on the WithDecoderLowmem setting.

View File

@ -21,6 +21,9 @@ type dict struct {
const dictMagic = "\x37\xa4\x30\xec"
// Maximum dictionary size for the reference implementation (1.5.3) is 2 GiB.
const dictMaxLength = 1 << 31
// ID returns the dictionary id or 0 if d is nil.
func (d *dict) ID() uint32 {
if d == nil {

View File

@ -4,6 +4,7 @@ import (
"errors"
"fmt"
"math"
"math/bits"
"runtime"
"strings"
)
@ -305,7 +306,13 @@ func WithLowerEncoderMem(b bool) EOption {
}
// WithEncoderDict allows to register a dictionary that will be used for the encode.
//
// The slice dict must be in the [dictionary format] produced by
// "zstd --train" from the Zstandard reference implementation.
//
// The encoder *may* choose to use no dictionary instead for certain payloads.
//
// [dictionary format]: https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#dictionary-format
func WithEncoderDict(dict []byte) EOption {
return func(o *encoderOptions) error {
d, err := loadDict(dict)
@ -316,3 +323,17 @@ func WithEncoderDict(dict []byte) EOption {
return nil
}
}
// WithEncoderDictRaw registers a dictionary that may be used by the encoder.
//
// The slice content may contain arbitrary data. It will be used as an initial
// history.
func WithEncoderDictRaw(id uint32, content []byte) EOption {
return func(o *encoderOptions) error {
if bits.UintSize > 32 && uint(len(content)) > dictMaxLength {
return fmt.Errorf("dictionary of size %d > 2GiB too large", len(content))
}
o.dict = &dict{id: id, content: content, offsets: [3]int{1, 4, 8}}
return nil
}
}

View File

@ -29,7 +29,7 @@ type frameDec struct {
FrameContentSize uint64
DictionaryID *uint32
DictionaryID uint32
HasCheckSum bool
SingleSegment bool
}
@ -155,7 +155,7 @@ func (d *frameDec) reset(br byteBuffer) error {
// Read Dictionary_ID
// https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#dictionary_id
d.DictionaryID = nil
d.DictionaryID = 0
if size := fhd & 3; size != 0 {
if size == 3 {
size = 4
@ -178,11 +178,7 @@ func (d *frameDec) reset(br byteBuffer) error {
if debugDecoder {
println("Dict size", size, "ID:", id)
}
if id > 0 {
// ID 0 means "sorry, no dictionary anyway".
// https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#dictionary-format
d.DictionaryID = &id
}
d.DictionaryID = id
}
// Read Frame_Content_Size

View File

@ -72,7 +72,6 @@ var (
ErrDecoderSizeExceeded = errors.New("decompressed size exceeds configured limit")
// ErrUnknownDictionary is returned if the dictionary ID is unknown.
// For the time being dictionaries are not supported.
ErrUnknownDictionary = errors.New("unknown dictionary")
// ErrFrameSizeExceeded is returned if the stated frame size is exceeded.

14
vendor/github.com/sigstore/fulcio/COPYRIGHT.txt generated vendored Normal file
View File

@ -0,0 +1,14 @@
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.

201
vendor/github.com/sigstore/fulcio/LICENSE generated vendored Normal file
View File

@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.

View File

@ -0,0 +1,17 @@
// Copyright 2022 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 certificate contains helpers for getting data from Fulcio issued
// x509 certificates.
package certificate

View File

@ -0,0 +1,132 @@
// Copyright 2022 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 certificate
import (
"crypto/x509/pkix"
"encoding/asn1"
"errors"
)
var (
OIDIssuer = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 1}
OIDGitHubWorkflowTrigger = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 2}
OIDGitHubWorkflowSHA = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 3}
OIDGitHubWorkflowName = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 4}
OIDGitHubWorkflowRepository = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 5}
OIDGitHubWorkflowRef = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 6}
OIDOtherName = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 7}
)
// Extensions contains all custom x509 extensions defined by Fulcio
type Extensions struct {
// NB: New extensions must be added here and documented
// at docs/oidc-info.md
// The OIDC issuer. Should match `iss` claim of ID token or, in the case of
// a federated login like Dex it should match the issuer URL of the
// upstream issuer. The issuer is not set the extensions are invalid and
// will fail to render.
Issuer string // OID 1.3.6.1.4.1.57264.1.1
// Triggering event of the Github Workflow. Matches the `event_name` claim of ID
// tokens from Github Actions
GithubWorkflowTrigger string // OID 1.3.6.1.4.1.57264.1.2
// SHA of git commit being built in Github Actions. Matches the `sha` claim of ID
// tokens from Github Actions
GithubWorkflowSHA string // OID 1.3.6.1.4.1.57264.1.3
// Name of Github Actions Workflow. Matches the `workflow` claim of the ID
// tokens from Github Actions
GithubWorkflowName string // OID 1.3.6.1.4.1.57264.1.4
// Repository of the Github Actions Workflow. Matches the `repository` claim of the ID
// tokens from Github Actions
GithubWorkflowRepository string // OID 1.3.6.1.4.1.57264.1.5
// Git Ref of the Github Actions Workflow. Matches the `ref` claim of the ID tokens
// from Github Actions
GithubWorkflowRef string // 1.3.6.1.4.1.57264.1.6
}
func (e Extensions) Render() ([]pkix.Extension, error) {
var exts []pkix.Extension
if e.Issuer != "" {
exts = append(exts, pkix.Extension{
Id: OIDIssuer,
Value: []byte(e.Issuer),
})
} else {
return nil, errors.New("extensions must have a non-empty issuer url")
}
if e.GithubWorkflowTrigger != "" {
exts = append(exts, pkix.Extension{
Id: OIDGitHubWorkflowTrigger,
Value: []byte(e.GithubWorkflowTrigger),
})
}
if e.GithubWorkflowSHA != "" {
exts = append(exts, pkix.Extension{
Id: OIDGitHubWorkflowSHA,
Value: []byte(e.GithubWorkflowSHA),
})
}
if e.GithubWorkflowName != "" {
exts = append(exts, pkix.Extension{
Id: OIDGitHubWorkflowName,
Value: []byte(e.GithubWorkflowName),
})
}
if e.GithubWorkflowRepository != "" {
exts = append(exts, pkix.Extension{
Id: OIDGitHubWorkflowRepository,
Value: []byte(e.GithubWorkflowRepository),
})
}
if e.GithubWorkflowRef != "" {
exts = append(exts, pkix.Extension{
Id: OIDGitHubWorkflowRef,
Value: []byte(e.GithubWorkflowRef),
})
}
return exts, nil
}
func ParseExtensions(ext []pkix.Extension) (Extensions, error) {
out := Extensions{}
for _, e := range ext {
switch {
case e.Id.Equal(OIDIssuer):
out.Issuer = string(e.Value)
case e.Id.Equal(OIDGitHubWorkflowTrigger):
out.GithubWorkflowTrigger = string(e.Value)
case e.Id.Equal(OIDGitHubWorkflowSHA):
out.GithubWorkflowSHA = string(e.Value)
case e.Id.Equal(OIDGitHubWorkflowName):
out.GithubWorkflowName = string(e.Value)
case e.Id.Equal(OIDGitHubWorkflowRepository):
out.GithubWorkflowRepository = string(e.Value)
case e.Id.Equal(OIDGitHubWorkflowRef):
out.GithubWorkflowRef = string(e.Value)
}
}
// We only ever return nil, but leaving error in place so that we can add
// more complex parsing of fields in a backwards compatible way if needed.
return out, nil
}

17
vendor/modules.txt vendored
View File

@ -98,7 +98,7 @@ github.com/containernetworking/cni/pkg/version
# github.com/containernetworking/plugins v1.2.0
## explicit; go 1.17
github.com/containernetworking/plugins/pkg/ns
# github.com/containers/buildah v1.28.1-0.20230118214707-42f2b38574c4
# github.com/containers/buildah v1.28.1-0.20230120225201-4b72f055f1c9
## explicit; go 1.17
github.com/containers/buildah
github.com/containers/buildah/bind
@ -121,7 +121,7 @@ github.com/containers/buildah/pkg/rusage
github.com/containers/buildah/pkg/sshagent
github.com/containers/buildah/pkg/util
github.com/containers/buildah/util
# github.com/containers/common v0.50.2-0.20230118184424-57606d3b130f
# github.com/containers/common v0.51.0
## explicit; go 1.17
github.com/containers/common/libimage
github.com/containers/common/libimage/define
@ -175,7 +175,7 @@ github.com/containers/common/version
# github.com/containers/conmon v2.0.20+incompatible
## explicit
github.com/containers/conmon/runner/config
# github.com/containers/image/v5 v5.23.1-0.20230118141642-5e9b17d07ceb
# github.com/containers/image/v5 v5.24.0
## explicit; go 1.17
github.com/containers/image/v5/copy
github.com/containers/image/v5/directory
@ -242,10 +242,10 @@ github.com/containers/image/v5/transports
github.com/containers/image/v5/transports/alltransports
github.com/containers/image/v5/types
github.com/containers/image/v5/version
# github.com/containers/libtrust v0.0.0-20200511145503-9c3a6c22cd9a
# github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01
## explicit
github.com/containers/libtrust
# github.com/containers/ocicrypt v1.1.7-0.20230115130455-e0cec6f7be0d
# github.com/containers/ocicrypt v1.1.7
## explicit; go 1.16
github.com/containers/ocicrypt
github.com/containers/ocicrypt/blockcipher
@ -272,7 +272,7 @@ github.com/containers/psgo/internal/dev
github.com/containers/psgo/internal/host
github.com/containers/psgo/internal/proc
github.com/containers/psgo/internal/process
# github.com/containers/storage v1.45.2-0.20230117181605-d5792d2dbc18
# github.com/containers/storage v1.45.3
## explicit; go 1.17
github.com/containers/storage
github.com/containers/storage/drivers
@ -535,7 +535,7 @@ github.com/josharian/intern
# github.com/json-iterator/go v1.1.12
## explicit; go 1.12
github.com/json-iterator/go
# github.com/klauspost/compress v1.15.14
# github.com/klauspost/compress v1.15.15
## explicit; go 1.17
github.com/klauspost/compress
github.com/klauspost/compress/flate
@ -735,6 +735,9 @@ github.com/rootless-containers/rootlesskit/pkg/port/portutil
# github.com/seccomp/libseccomp-golang v0.10.0
## explicit; go 1.14
github.com/seccomp/libseccomp-golang
# github.com/sigstore/fulcio v1.0.0
## explicit; go 1.18
github.com/sigstore/fulcio/pkg/certificate
# github.com/sigstore/rekor v1.0.1
## explicit; go 1.18
github.com/sigstore/rekor/pkg/generated/models