vendor: update buildkit to v0.28.0-rc1

Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
This commit is contained in:
Tonis Tiigi
2026-02-24 14:19:34 -08:00
parent 8967e9f760
commit dd2a620465
273 changed files with 23061 additions and 63650 deletions
+193 -13
View File
@@ -6,6 +6,7 @@ import (
"encoding/json"
"os"
"path"
"slices"
"strconv"
"strings"
@@ -96,6 +97,123 @@ func (s *SourceOp) Inputs() []Output {
return nil
}
type ImageBlobInfo struct {
constraintsWrapper
fileinfoWrapper
sessionID string
storeID string
}
type ImageBlobOption interface {
SetImageBlobOption(*ImageBlobInfo)
}
type FileInfoOption interface {
HTTPOption
ImageBlobOption
}
func ImageBlob(ref string, opts ...ImageBlobOption) State {
bi := &ImageBlobInfo{}
for _, o := range opts {
o.SetImageBlobOption(bi)
}
attrs := map[string]string{}
if bi.Filename != "" {
attrs[pb.AttrHTTPFilename] = bi.Filename
}
if bi.Perm != 0 {
attrs[pb.AttrHTTPPerm] = "0" + strconv.FormatInt(int64(bi.Perm), 8)
}
if bi.UID != 0 {
attrs[pb.AttrHTTPUID] = strconv.Itoa(bi.UID)
}
if bi.GID != 0 {
attrs[pb.AttrHTTPGID] = strconv.Itoa(bi.GID)
}
addCap(&bi.Constraints, pb.CapSourceImageBlob)
var digested reference.Digested
r, err := reference.ParseNormalizedNamed(ref)
if err == nil {
if _, tagged := r.(reference.Tagged); tagged {
err = errors.Errorf("tagged image reference not allowed for blob reference")
} else if ref, ok := r.(reference.Digested); !ok {
err = errors.Errorf("checksum required in blob reference")
} else {
digested = ref
}
}
repoName := "invalid"
if digested != nil {
repoName = digested.String()
}
source := NewSource("docker-image+blob://"+repoName, attrs, bi.Constraints)
if err != nil {
source.err = err
}
return NewState(source.Output())
}
// OCILayoutBlob returns a state that represents a single digest-addressed blob from an OCI layout store.
func OCILayoutBlob(ref string, opts ...ImageBlobOption) State {
bi := &ImageBlobInfo{}
for _, o := range opts {
o.SetImageBlobOption(bi)
}
attrs := map[string]string{}
if bi.Filename != "" {
attrs[pb.AttrHTTPFilename] = bi.Filename
}
if bi.Perm != 0 {
attrs[pb.AttrHTTPPerm] = "0" + strconv.FormatInt(int64(bi.Perm), 8)
}
if bi.UID != 0 {
attrs[pb.AttrHTTPUID] = strconv.Itoa(bi.UID)
}
if bi.GID != 0 {
attrs[pb.AttrHTTPGID] = strconv.Itoa(bi.GID)
}
if bi.sessionID != "" {
attrs[pb.AttrOCILayoutSessionID] = bi.sessionID
}
if bi.storeID != "" {
attrs[pb.AttrOCILayoutStoreID] = bi.storeID
}
addCap(&bi.Constraints, pb.CapSourceImageBlob)
var digested reference.Digested
r, err := reference.ParseNormalizedNamed(ref)
if err == nil {
if _, tagged := r.(reference.Tagged); tagged {
err = errors.Errorf("tagged image reference not allowed for blob reference")
} else if ref, ok := r.(reference.Digested); !ok {
err = errors.Errorf("checksum required in blob reference")
} else {
digested = ref
}
}
repoName := "invalid"
if digested != nil {
repoName = digested.String()
}
source := NewSource("oci-layout+blob://"+repoName, attrs, bi.Constraints)
if err != nil {
source.err = err
}
return NewState(source.Output())
}
// Image returns a state that represents a docker image in a registry.
// Example:
//
@@ -197,6 +315,12 @@ func (fn imageOptionFunc) SetImageOption(ii *ImageInfo) {
fn(ii)
}
type imageBlobOptionFunc func(*ImageBlobInfo)
func (fn imageBlobOptionFunc) SetImageBlobOption(ib *ImageBlobInfo) {
fn(ib)
}
var MarkImageInternal = imageOptionFunc(func(ii *ImageInfo) {
ii.RecordType = "internal"
})
@@ -623,6 +747,14 @@ func OCIStore(sessionID string, storeID string) OCILayoutOption {
})
}
// ImageBlobOCIStore returns an [ImageBlobOption] that configures the OCI layout session/store used by [OCILayoutBlob].
func ImageBlobOCIStore(sessionID string, storeID string) ImageBlobOption {
return imageBlobOptionFunc(func(ib *ImageBlobInfo) {
ib.sessionID = sessionID
ib.storeID = storeID
})
}
func OCILayerLimit(limit int) OCILayoutOption {
return ociLayoutOptionFunc(func(oi *OCILayoutInfo) {
oi.layerLimit = &limit
@@ -705,21 +837,58 @@ func HTTP(url string, opts ...HTTPOption) State {
hi.Header.setAttrs(attrs)
addCap(&hi.Constraints, pb.CapSourceHTTPHeader)
}
if hi.Signature != nil {
if len(hi.Signature.PubKey) > 0 {
attrs[pb.AttrHTTPSignatureVerifyPubKey] = string(hi.Signature.PubKey)
}
if len(hi.Signature.Signature) > 0 {
attrs[pb.AttrHTTPSignatureVerify] = string(hi.Signature.Signature)
}
addCap(&hi.Constraints, pb.CapSourceHTTPSignatureVerify)
}
addCap(&hi.Constraints, pb.CapSourceHTTP)
source := NewSource(url, attrs, hi.Constraints)
return NewState(source.Output())
}
type fileInfo struct {
Filename string
Perm int
UID int
GID int
}
type fileinfoWrapper struct {
fileInfo
}
type fileInfoOptFunc func(f *fileInfo)
func (fn fileInfoOptFunc) SetHTTPOption(hi *HTTPInfo) {
fn(&hi.fileInfo)
}
func (fn fileInfoOptFunc) SetImageBlobOption(ib *ImageBlobInfo) {
fn(&ib.fileInfo)
}
// HTTPSignatureInfo configures detached-signature verification for HTTP
// sources. The current implementation uses inline armored signatures.
type HTTPSignatureInfo struct {
PubKey []byte
// Signature is an inline detached armored OpenPGP signature.
Signature []byte
}
type HTTPInfo struct {
constraintsWrapper
fileinfoWrapper
Checksum digest.Digest
Filename string
Perm int
UID int
GID int
AuthHeaderSecret string
Header *HTTPHeader
Signature *HTTPSignatureInfo
}
type HTTPOption interface {
@@ -738,22 +907,33 @@ func Checksum(dgst digest.Digest) HTTPOption {
})
}
func Chmod(perm os.FileMode) HTTPOption {
return httpOptionFunc(func(hi *HTTPInfo) {
hi.Perm = int(perm) & 0777
func Chmod(perm os.FileMode) FileInfoOption {
return fileInfoOptFunc(func(fi *fileInfo) {
fi.Perm = int(perm) & 0777
})
}
func Filename(name string) HTTPOption {
return httpOptionFunc(func(hi *HTTPInfo) {
hi.Filename = name
func Filename(name string) FileInfoOption {
return fileInfoOptFunc(func(fi *fileInfo) {
fi.Filename = name
})
}
func Chown(uid, gid int) HTTPOption {
func Chown(uid, gid int) FileInfoOption {
return fileInfoOptFunc(func(fi *fileInfo) {
fi.UID = uid
fi.GID = gid
})
}
// VerifyPGPSignature returns an [HTTPOption] for detached OpenPGP signature
// verification of the downloaded HTTP payload.
func VerifyPGPSignature(info HTTPSignatureInfo) HTTPOption {
return httpOptionFunc(func(hi *HTTPInfo) {
hi.UID = uid
hi.GID = gid
hi.Signature = &HTTPSignatureInfo{
PubKey: slices.Clone(info.PubKey),
Signature: slices.Clone(info.Signature),
}
})
}
+27 -3
View File
@@ -28,6 +28,7 @@ type Opt struct {
ImageOpt *ResolveImageOpt
OCILayoutOpt *ResolveOCILayoutOpt
GitOpt *ResolveGitOpt
HTTPOpt *ResolveHTTPOpt
}
type MetaResponse struct {
@@ -78,9 +79,32 @@ type ResolveGitResponse struct {
}
type ResolveHTTPResponse struct {
Digest digest.Digest
Filename string
LastModified *time.Time
Digest digest.Digest
Filename string
LastModified *time.Time
ChecksumResponse *ResolveHTTPChecksumResponse
}
type ResolveHTTPOpt struct {
ChecksumReq *ResolveHTTPChecksumRequest
}
type ResolveHTTPChecksumAlgo int
const (
ResolveHTTPChecksumAlgoSHA256 ResolveHTTPChecksumAlgo = iota
ResolveHTTPChecksumAlgoSHA384
ResolveHTTPChecksumAlgoSHA512
)
type ResolveHTTPChecksumRequest struct {
Algo ResolveHTTPChecksumAlgo
Suffix []byte
}
type ResolveHTTPChecksumResponse struct {
Digest string
Suffix []byte
}
type ResolveOCILayoutOpt struct {
+6
View File
@@ -526,6 +526,7 @@ type ConstraintsOpt interface {
RunOption
LocalOption
HTTPOption
ImageBlobOption
ImageOption
GitOption
OCILayoutOption
@@ -553,6 +554,10 @@ func (fn constraintsOptFunc) SetHTTPOption(hi *HTTPInfo) {
hi.applyConstraints(fn)
}
func (fn constraintsOptFunc) SetImageBlobOption(ii *ImageBlobInfo) {
ii.applyConstraints(fn)
}
func (fn constraintsOptFunc) SetImageOption(ii *ImageInfo) {
ii.applyConstraints(fn)
}
@@ -736,6 +741,7 @@ var (
LinuxS390x = Platform(ocispecs.Platform{OS: "linux", Architecture: "s390x"})
LinuxPpc64 = Platform(ocispecs.Platform{OS: "linux", Architecture: "ppc64"})
LinuxPpc64le = Platform(ocispecs.Platform{OS: "linux", Architecture: "ppc64le"})
LinuxRiscv64 = Platform(ocispecs.Platform{OS: "linux", Architecture: "riscv64"})
Darwin = Platform(ocispecs.Platform{OS: "darwin", Architecture: "amd64"})
Windows = Platform(ocispecs.Platform{OS: "windows", Architecture: "amd64"})
)
+1 -1
View File
@@ -15,7 +15,7 @@ const (
const (
defaultSBOMGenerator = "docker/buildkit-syft-scanner:stable-1"
defaultSLSAVersion = string(provenancetypes.ProvenanceSLSA02)
defaultSLSAVersion = string(provenancetypes.ProvenanceSLSA1)
)
func Filter(v map[string]string) map[string]string {
+39
View File
@@ -479,6 +479,9 @@ func (c *grpcClient) ResolveSourceMetadata(ctx context.Context, op *opspb.Source
} else if v, ok := strings.CutPrefix(op.Identifier, "oci-layout://"); ok {
ref = v
} else {
if opt.HTTPOpt != nil && opt.HTTPOpt.ChecksumReq != nil {
return nil, errors.New("http checksum request requires source metadata resolver support")
}
return &sourceresolver.MetaResponse{Op: op}, nil
}
retRef, dgst, config, err := c.ResolveImageConfig(ctx, ref, opt)
@@ -541,6 +544,18 @@ func (c *grpcClient) ResolveSourceMetadata(ctx context.Context, op *opspb.Source
ReturnObject: opt.GitOpt.ReturnObject,
}
}
if opt.HTTPOpt != nil && opt.HTTPOpt.ChecksumReq != nil {
algo, err := toPBHTTPChecksumAlgo(opt.HTTPOpt.ChecksumReq.Algo)
if err != nil {
return nil, err
}
req.HTTP = &pb.ResolveSourceHTTPRequest{
ChecksumRequest: &pb.ChecksumRequest{
Algo: algo,
Suffix: slices.Clone(opt.HTTPOpt.ChecksumReq.Suffix),
},
}
}
resp, err := c.client.ResolveSourceMeta(ctx, req)
if err != nil {
@@ -576,10 +591,34 @@ func (c *grpcClient) ResolveSourceMetadata(ctx context.Context, op *opspb.Source
tm := resp.HTTP.LastModified.AsTime()
r.HTTP.LastModified = &tm
}
if resp.HTTP.ChecksumResponse != nil {
r.HTTP.ChecksumResponse = &sourceresolver.ResolveHTTPChecksumResponse{
Digest: resp.HTTP.ChecksumResponse.Digest,
Suffix: slices.Clone(resp.HTTP.ChecksumResponse.Suffix),
}
}
}
if opt.HTTPOpt != nil && opt.HTTPOpt.ChecksumReq != nil {
if resp.HTTP == nil || resp.HTTP.ChecksumResponse == nil {
return nil, errors.New("http checksum request was sent but response did not include checksum response")
}
}
return r, nil
}
func toPBHTTPChecksumAlgo(in sourceresolver.ResolveHTTPChecksumAlgo) (pb.ChecksumRequest_ChecksumAlgo, error) {
switch in {
case sourceresolver.ResolveHTTPChecksumAlgoSHA256:
return pb.ChecksumRequest_CHECKSUM_ALGO_SHA256, nil
case sourceresolver.ResolveHTTPChecksumAlgoSHA384:
return pb.ChecksumRequest_CHECKSUM_ALGO_SHA384, nil
case sourceresolver.ResolveHTTPChecksumAlgoSHA512:
return pb.ChecksumRequest_CHECKSUM_ALGO_SHA512, nil
default:
return pb.ChecksumRequest_CHECKSUM_ALGO_SHA256, errors.Errorf("invalid http checksum algorithm: %d", in)
}
}
func imgResponseFromPB(resp *pb.ResolveSourceImageResponse) *sourceresolver.ResolveImageResponse {
r := &sourceresolver.ResolveImageResponse{
Digest: digest.Digest(resp.Digest),
File diff suppressed because it is too large Load Diff
+21
View File
@@ -142,6 +142,7 @@ message ResolveSourceMetaRequest {
string ResolveMode = 4;
ResolveSourceGitRequest Git = 5;
ResolveSourceImageRequest Image = 6;
ResolveSourceHTTPRequest HTTP = 7;
repeated moby.buildkit.v1.sourcepolicy.Policy SourcePolicies = 8;
}
@@ -189,6 +190,26 @@ message ResolveSourceHTTPResponse {
string Checksum = 1;
string Filename = 2;
google.protobuf.Timestamp LastModified = 3;
ChecksumResponse ChecksumResponse = 4;
}
message ResolveSourceHTTPRequest {
ChecksumRequest ChecksumRequest = 1;
}
message ChecksumRequest {
enum ChecksumAlgo {
CHECKSUM_ALGO_SHA256 = 0;
CHECKSUM_ALGO_SHA384 = 1;
CHECKSUM_ALGO_SHA512 = 2;
}
ChecksumAlgo Algo = 1;
bytes Suffix = 2;
}
message ChecksumResponse {
string Digest = 1;
bytes Suffix = 2;
}
message SolveRequest {
@@ -387,6 +387,7 @@ func (m *ResolveSourceMetaRequest) CloneVT() *ResolveSourceMetaRequest {
r.ResolveMode = m.ResolveMode
r.Git = m.Git.CloneVT()
r.Image = m.Image.CloneVT()
r.HTTP = m.HTTP.CloneVT()
if rhs := m.SourcePolicies; rhs != nil {
tmpContainer := make([]*pb1.Policy, len(rhs))
for k, v := range rhs {
@@ -556,6 +557,7 @@ func (m *ResolveSourceHTTPResponse) CloneVT() *ResolveSourceHTTPResponse {
r.Checksum = m.Checksum
r.Filename = m.Filename
r.LastModified = (*timestamp.Timestamp)((*timestamppb.Timestamp)(m.LastModified).CloneVT())
r.ChecksumResponse = m.ChecksumResponse.CloneVT()
if len(m.unknownFields) > 0 {
r.unknownFields = make([]byte, len(m.unknownFields))
copy(r.unknownFields, m.unknownFields)
@@ -567,6 +569,67 @@ func (m *ResolveSourceHTTPResponse) CloneMessageVT() proto.Message {
return m.CloneVT()
}
func (m *ResolveSourceHTTPRequest) CloneVT() *ResolveSourceHTTPRequest {
if m == nil {
return (*ResolveSourceHTTPRequest)(nil)
}
r := new(ResolveSourceHTTPRequest)
r.ChecksumRequest = m.ChecksumRequest.CloneVT()
if len(m.unknownFields) > 0 {
r.unknownFields = make([]byte, len(m.unknownFields))
copy(r.unknownFields, m.unknownFields)
}
return r
}
func (m *ResolveSourceHTTPRequest) CloneMessageVT() proto.Message {
return m.CloneVT()
}
func (m *ChecksumRequest) CloneVT() *ChecksumRequest {
if m == nil {
return (*ChecksumRequest)(nil)
}
r := new(ChecksumRequest)
r.Algo = m.Algo
if rhs := m.Suffix; rhs != nil {
tmpBytes := make([]byte, len(rhs))
copy(tmpBytes, rhs)
r.Suffix = tmpBytes
}
if len(m.unknownFields) > 0 {
r.unknownFields = make([]byte, len(m.unknownFields))
copy(r.unknownFields, m.unknownFields)
}
return r
}
func (m *ChecksumRequest) CloneMessageVT() proto.Message {
return m.CloneVT()
}
func (m *ChecksumResponse) CloneVT() *ChecksumResponse {
if m == nil {
return (*ChecksumResponse)(nil)
}
r := new(ChecksumResponse)
r.Digest = m.Digest
if rhs := m.Suffix; rhs != nil {
tmpBytes := make([]byte, len(rhs))
copy(tmpBytes, rhs)
r.Suffix = tmpBytes
}
if len(m.unknownFields) > 0 {
r.unknownFields = make([]byte, len(m.unknownFields))
copy(r.unknownFields, m.unknownFields)
}
return r
}
func (m *ChecksumResponse) CloneMessageVT() proto.Message {
return m.CloneVT()
}
func (m *SolveRequest) CloneVT() *SolveRequest {
if m == nil {
return (*SolveRequest)(nil)
@@ -1870,6 +1933,9 @@ func (this *ResolveSourceMetaRequest) EqualVT(that *ResolveSourceMetaRequest) bo
if !this.Image.EqualVT(that.Image) {
return false
}
if !this.HTTP.EqualVT(that.HTTP) {
return false
}
if len(this.SourcePolicies) != len(that.SourcePolicies) {
return false
}
@@ -2100,6 +2166,9 @@ func (this *ResolveSourceHTTPResponse) EqualVT(that *ResolveSourceHTTPResponse)
if !(*timestamppb.Timestamp)(this.LastModified).EqualVT((*timestamppb.Timestamp)(that.LastModified)) {
return false
}
if !this.ChecksumResponse.EqualVT(that.ChecksumResponse) {
return false
}
return string(this.unknownFields) == string(that.unknownFields)
}
@@ -2110,6 +2179,69 @@ func (this *ResolveSourceHTTPResponse) EqualMessageVT(thatMsg proto.Message) boo
}
return this.EqualVT(that)
}
func (this *ResolveSourceHTTPRequest) EqualVT(that *ResolveSourceHTTPRequest) bool {
if this == that {
return true
} else if this == nil || that == nil {
return false
}
if !this.ChecksumRequest.EqualVT(that.ChecksumRequest) {
return false
}
return string(this.unknownFields) == string(that.unknownFields)
}
func (this *ResolveSourceHTTPRequest) EqualMessageVT(thatMsg proto.Message) bool {
that, ok := thatMsg.(*ResolveSourceHTTPRequest)
if !ok {
return false
}
return this.EqualVT(that)
}
func (this *ChecksumRequest) EqualVT(that *ChecksumRequest) bool {
if this == that {
return true
} else if this == nil || that == nil {
return false
}
if this.Algo != that.Algo {
return false
}
if string(this.Suffix) != string(that.Suffix) {
return false
}
return string(this.unknownFields) == string(that.unknownFields)
}
func (this *ChecksumRequest) EqualMessageVT(thatMsg proto.Message) bool {
that, ok := thatMsg.(*ChecksumRequest)
if !ok {
return false
}
return this.EqualVT(that)
}
func (this *ChecksumResponse) EqualVT(that *ChecksumResponse) bool {
if this == that {
return true
} else if this == nil || that == nil {
return false
}
if this.Digest != that.Digest {
return false
}
if string(this.Suffix) != string(that.Suffix) {
return false
}
return string(this.unknownFields) == string(that.unknownFields)
}
func (this *ChecksumResponse) EqualMessageVT(thatMsg proto.Message) bool {
that, ok := thatMsg.(*ChecksumResponse)
if !ok {
return false
}
return this.EqualVT(that)
}
func (this *SolveRequest) EqualVT(that *SolveRequest) bool {
if this == that {
return true
@@ -4090,6 +4222,16 @@ func (m *ResolveSourceMetaRequest) MarshalToSizedBufferVT(dAtA []byte) (int, err
dAtA[i] = 0x42
}
}
if m.HTTP != nil {
size, err := m.HTTP.MarshalToSizedBufferVT(dAtA[:i])
if err != nil {
return 0, err
}
i -= size
i = protohelpers.EncodeVarint(dAtA, i, uint64(size))
i--
dAtA[i] = 0x3a
}
if m.Image != nil {
size, err := m.Image.MarshalToSizedBufferVT(dAtA[:i])
if err != nil {
@@ -4565,6 +4707,16 @@ func (m *ResolveSourceHTTPResponse) MarshalToSizedBufferVT(dAtA []byte) (int, er
i -= len(m.unknownFields)
copy(dAtA[i:], m.unknownFields)
}
if m.ChecksumResponse != nil {
size, err := m.ChecksumResponse.MarshalToSizedBufferVT(dAtA[:i])
if err != nil {
return 0, err
}
i -= size
i = protohelpers.EncodeVarint(dAtA, i, uint64(size))
i--
dAtA[i] = 0x22
}
if m.LastModified != nil {
size, err := (*timestamppb.Timestamp)(m.LastModified).MarshalToSizedBufferVT(dAtA[:i])
if err != nil {
@@ -4592,6 +4744,141 @@ func (m *ResolveSourceHTTPResponse) MarshalToSizedBufferVT(dAtA []byte) (int, er
return len(dAtA) - i, nil
}
func (m *ResolveSourceHTTPRequest) MarshalVT() (dAtA []byte, err error) {
if m == nil {
return nil, nil
}
size := m.SizeVT()
dAtA = make([]byte, size)
n, err := m.MarshalToSizedBufferVT(dAtA[:size])
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *ResolveSourceHTTPRequest) MarshalToVT(dAtA []byte) (int, error) {
size := m.SizeVT()
return m.MarshalToSizedBufferVT(dAtA[:size])
}
func (m *ResolveSourceHTTPRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) {
if m == nil {
return 0, nil
}
i := len(dAtA)
_ = i
var l int
_ = l
if m.unknownFields != nil {
i -= len(m.unknownFields)
copy(dAtA[i:], m.unknownFields)
}
if m.ChecksumRequest != nil {
size, err := m.ChecksumRequest.MarshalToSizedBufferVT(dAtA[:i])
if err != nil {
return 0, err
}
i -= size
i = protohelpers.EncodeVarint(dAtA, i, uint64(size))
i--
dAtA[i] = 0xa
}
return len(dAtA) - i, nil
}
func (m *ChecksumRequest) MarshalVT() (dAtA []byte, err error) {
if m == nil {
return nil, nil
}
size := m.SizeVT()
dAtA = make([]byte, size)
n, err := m.MarshalToSizedBufferVT(dAtA[:size])
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *ChecksumRequest) MarshalToVT(dAtA []byte) (int, error) {
size := m.SizeVT()
return m.MarshalToSizedBufferVT(dAtA[:size])
}
func (m *ChecksumRequest) MarshalToSizedBufferVT(dAtA []byte) (int, error) {
if m == nil {
return 0, nil
}
i := len(dAtA)
_ = i
var l int
_ = l
if m.unknownFields != nil {
i -= len(m.unknownFields)
copy(dAtA[i:], m.unknownFields)
}
if len(m.Suffix) > 0 {
i -= len(m.Suffix)
copy(dAtA[i:], m.Suffix)
i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Suffix)))
i--
dAtA[i] = 0x12
}
if m.Algo != 0 {
i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Algo))
i--
dAtA[i] = 0x8
}
return len(dAtA) - i, nil
}
func (m *ChecksumResponse) MarshalVT() (dAtA []byte, err error) {
if m == nil {
return nil, nil
}
size := m.SizeVT()
dAtA = make([]byte, size)
n, err := m.MarshalToSizedBufferVT(dAtA[:size])
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *ChecksumResponse) MarshalToVT(dAtA []byte) (int, error) {
size := m.SizeVT()
return m.MarshalToSizedBufferVT(dAtA[:size])
}
func (m *ChecksumResponse) MarshalToSizedBufferVT(dAtA []byte) (int, error) {
if m == nil {
return 0, nil
}
i := len(dAtA)
_ = i
var l int
_ = l
if m.unknownFields != nil {
i -= len(m.unknownFields)
copy(dAtA[i:], m.unknownFields)
}
if len(m.Suffix) > 0 {
i -= len(m.Suffix)
copy(dAtA[i:], m.Suffix)
i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Suffix)))
i--
dAtA[i] = 0x12
}
if len(m.Digest) > 0 {
i -= len(m.Digest)
copy(dAtA[i:], m.Digest)
i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Digest)))
i--
dAtA[i] = 0xa
}
return len(dAtA) - i, nil
}
func (m *SolveRequest) MarshalVT() (dAtA []byte, err error) {
if m == nil {
return nil, nil
@@ -6810,6 +7097,10 @@ func (m *ResolveSourceMetaRequest) SizeVT() (n int) {
l = m.Image.SizeVT()
n += 1 + l + protohelpers.SizeOfVarint(uint64(l))
}
if m.HTTP != nil {
l = m.HTTP.SizeVT()
n += 1 + l + protohelpers.SizeOfVarint(uint64(l))
}
if len(m.SourcePolicies) > 0 {
for _, e := range m.SourcePolicies {
l = e.SizeVT()
@@ -6992,6 +7283,59 @@ func (m *ResolveSourceHTTPResponse) SizeVT() (n int) {
l = (*timestamppb.Timestamp)(m.LastModified).SizeVT()
n += 1 + l + protohelpers.SizeOfVarint(uint64(l))
}
if m.ChecksumResponse != nil {
l = m.ChecksumResponse.SizeVT()
n += 1 + l + protohelpers.SizeOfVarint(uint64(l))
}
n += len(m.unknownFields)
return n
}
func (m *ResolveSourceHTTPRequest) SizeVT() (n int) {
if m == nil {
return 0
}
var l int
_ = l
if m.ChecksumRequest != nil {
l = m.ChecksumRequest.SizeVT()
n += 1 + l + protohelpers.SizeOfVarint(uint64(l))
}
n += len(m.unknownFields)
return n
}
func (m *ChecksumRequest) SizeVT() (n int) {
if m == nil {
return 0
}
var l int
_ = l
if m.Algo != 0 {
n += 1 + protohelpers.SizeOfVarint(uint64(m.Algo))
}
l = len(m.Suffix)
if l > 0 {
n += 1 + l + protohelpers.SizeOfVarint(uint64(l))
}
n += len(m.unknownFields)
return n
}
func (m *ChecksumResponse) SizeVT() (n int) {
if m == nil {
return 0
}
var l int
_ = l
l = len(m.Digest)
if l > 0 {
n += 1 + l + protohelpers.SizeOfVarint(uint64(l))
}
l = len(m.Suffix)
if l > 0 {
n += 1 + l + protohelpers.SizeOfVarint(uint64(l))
}
n += len(m.unknownFields)
return n
}
@@ -10316,6 +10660,42 @@ func (m *ResolveSourceMetaRequest) UnmarshalVT(dAtA []byte) error {
return err
}
iNdEx = postIndex
case 7:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field HTTP", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return protohelpers.ErrInvalidLength
}
postIndex := iNdEx + msglen
if postIndex < 0 {
return protohelpers.ErrInvalidLength
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
if m.HTTP == nil {
m.HTTP = &ResolveSourceHTTPRequest{}
}
if err := m.HTTP.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
case 8:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field SourcePolicies", wireType)
@@ -11566,6 +11946,350 @@ func (m *ResolveSourceHTTPResponse) UnmarshalVT(dAtA []byte) error {
return err
}
iNdEx = postIndex
case 4:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field ChecksumResponse", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return protohelpers.ErrInvalidLength
}
postIndex := iNdEx + msglen
if postIndex < 0 {
return protohelpers.ErrInvalidLength
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
if m.ChecksumResponse == nil {
m.ChecksumResponse = &ChecksumResponse{}
}
if err := m.ChecksumResponse.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := protohelpers.Skip(dAtA[iNdEx:])
if err != nil {
return err
}
if (skippy < 0) || (iNdEx+skippy) < 0 {
return protohelpers.ErrInvalidLength
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *ResolveSourceHTTPRequest) UnmarshalVT(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: ResolveSourceHTTPRequest: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: ResolveSourceHTTPRequest: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field ChecksumRequest", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return protohelpers.ErrInvalidLength
}
postIndex := iNdEx + msglen
if postIndex < 0 {
return protohelpers.ErrInvalidLength
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
if m.ChecksumRequest == nil {
m.ChecksumRequest = &ChecksumRequest{}
}
if err := m.ChecksumRequest.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := protohelpers.Skip(dAtA[iNdEx:])
if err != nil {
return err
}
if (skippy < 0) || (iNdEx+skippy) < 0 {
return protohelpers.ErrInvalidLength
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *ChecksumRequest) UnmarshalVT(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: ChecksumRequest: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: ChecksumRequest: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Algo", wireType)
}
m.Algo = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.Algo |= ChecksumRequest_ChecksumAlgo(b&0x7F) << shift
if b < 0x80 {
break
}
}
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Suffix", wireType)
}
var byteLen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
byteLen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if byteLen < 0 {
return protohelpers.ErrInvalidLength
}
postIndex := iNdEx + byteLen
if postIndex < 0 {
return protohelpers.ErrInvalidLength
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Suffix = append(m.Suffix[:0], dAtA[iNdEx:postIndex]...)
if m.Suffix == nil {
m.Suffix = []byte{}
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := protohelpers.Skip(dAtA[iNdEx:])
if err != nil {
return err
}
if (skippy < 0) || (iNdEx+skippy) < 0 {
return protohelpers.ErrInvalidLength
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *ChecksumResponse) UnmarshalVT(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: ChecksumResponse: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: ChecksumResponse: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Digest", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return protohelpers.ErrInvalidLength
}
postIndex := iNdEx + intStringLen
if postIndex < 0 {
return protohelpers.ErrInvalidLength
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Digest = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Suffix", wireType)
}
var byteLen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
byteLen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if byteLen < 0 {
return protohelpers.ErrInvalidLength
}
postIndex := iNdEx + byteLen
if postIndex < 0 {
return protohelpers.ErrInvalidLength
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Suffix = append(m.Suffix[:0], dAtA[iNdEx:postIndex]...)
if m.Suffix == nil {
m.Suffix = []byte{}
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := protohelpers.Skip(dAtA[iNdEx:])
+11 -4
View File
@@ -62,6 +62,12 @@ type ImageSource struct {
Local bool
}
type ImageBlobSource struct {
Ref string
Digest digest.Digest
Local bool
}
type GitSource struct {
URL string
Commit string
@@ -87,10 +93,11 @@ type SSH struct {
}
type Sources struct {
Images []ImageSource
Git []GitSource
HTTP []HTTPSource
Local []LocalSource
Images []ImageSource
ImageBlobs []ImageBlobSource
Git []GitSource
HTTP []HTTPSource
Local []LocalSource
}
func (ps *ProvenanceSLSA) Validate() error {
+2
View File
@@ -32,6 +32,8 @@ const AttrHTTPUID = "http.uid"
const AttrHTTPGID = "http.gid"
const AttrHTTPAuthHeaderSecret = "http.authheadersecret"
const AttrHTTPHeaderPrefix = "http.header."
const AttrHTTPSignatureVerifyPubKey = "http.sig.pubkey"
const AttrHTTPSignatureVerify = "http.sig.signature"
const AttrImageResolveMode = "image.resolvemode"
const AttrImageResolveModeDefault = "default"
+17 -2
View File
@@ -40,8 +40,11 @@ const (
CapSourceHTTPChecksum apicaps.CapID = "source.http.checksum"
CapSourceHTTPPerm apicaps.CapID = "source.http.perm"
// NOTE the historical typo
CapSourceHTTPUIDGID apicaps.CapID = "soruce.http.uidgid"
CapSourceHTTPHeader apicaps.CapID = "source.http.header"
CapSourceHTTPUIDGID apicaps.CapID = "soruce.http.uidgid"
CapSourceHTTPHeader apicaps.CapID = "source.http.header"
CapSourceHTTPSignatureVerify apicaps.CapID = "source.http.signatureverify"
CapSourceImageBlob apicaps.CapID = "source.imageblob"
CapSourceOCILayout apicaps.CapID = "source.ocilayout"
@@ -288,6 +291,18 @@ func init() {
Status: apicaps.CapStatusExperimental,
})
Caps.Init(apicaps.Cap{
ID: CapSourceHTTPSignatureVerify,
Enabled: true,
Status: apicaps.CapStatusExperimental,
})
Caps.Init(apicaps.Cap{
ID: CapSourceImageBlob,
Enabled: true,
Status: apicaps.CapStatusExperimental,
})
Caps.Init(apicaps.Cap{
ID: CapSourceOCILayout,
Enabled: true,
+8 -6
View File
@@ -1,10 +1,12 @@
package srctypes
const (
DockerImageScheme = "docker-image"
GitScheme = "git"
LocalScheme = "local"
HTTPScheme = "http"
HTTPSScheme = "https"
OCIScheme = "oci-layout"
DockerImageScheme = "docker-image"
DockerImageBlobScheme = "docker-image+blob"
GitScheme = "git"
LocalScheme = "local"
HTTPScheme = "http"
HTTPSScheme = "https"
OCIScheme = "oci-layout"
OCIBlobScheme = "oci-layout+blob"
)
+16
View File
@@ -19,6 +19,7 @@ import (
type Buffer interface {
content.Provider
content.Ingester
content.IngestManager
content.Manager
}
@@ -119,6 +120,21 @@ func (b *buffer) Writer(ctx context.Context, opts ...content.WriterOpt) (content
}, nil
}
func (b *buffer) Status(ctx context.Context, ref string) (content.Status, error) {
return content.Status{}, cerrdefs.ErrNotFound
}
func (b *buffer) ListStatuses(ctx context.Context, filters ...string) ([]content.Status, error) {
return nil, nil
}
func (b *buffer) Abort(ctx context.Context, ref string) error {
b.mu.Lock()
delete(b.refs, ref)
b.mu.Unlock()
return nil
}
func (b *buffer) ReaderAt(ctx context.Context, desc ocispecs.Descriptor) (content.ReaderAt, error) {
r, err := b.getBytesReader(desc.Digest)
if err != nil {
+18
View File
@@ -52,11 +52,28 @@ func (p *ReferrersProviderBuffer) ReaderAt(ctx context.Context, desc ocispecs.De
}
return nil, err
}
if st, err := cw.Status(); err == nil {
if st.Offset > 0 {
if err := cw.Truncate(0); err != nil {
cw.Close()
return nil, err
}
}
}
abort := func() {
_ = p.cache.Abort(ctx, desc.Digest.String())
}
defer func() {
if abort != nil {
abort()
}
}()
ra, err := p.p.ReaderAt(ctx, desc)
if err != nil {
cw.Close()
return nil, err
}
defer ra.Close()
if err := content.CopyReaderAt(cw, ra, ra.Size()); err != nil {
cw.Close()
return nil, err
@@ -65,6 +82,7 @@ func (p *ReferrersProviderBuffer) ReaderAt(ctx context.Context, desc ocispecs.De
cw.Close()
return nil, err
}
abort = nil
ra, err = p.cache.ReaderAt(ctx, desc)
if err != nil {
return nil, err
+23 -172
View File
@@ -2,39 +2,23 @@ package gitsign
import (
"bytes"
"crypto"
"crypto/rsa"
"encoding/pem"
"io"
"strings"
"time"
"github.com/ProtonMail/go-crypto/openpgp"
"github.com/ProtonMail/go-crypto/openpgp/armor"
"github.com/ProtonMail/go-crypto/openpgp/packet"
"github.com/hiddeco/sshsig"
"github.com/moby/buildkit/util/gitutil/gitobject"
"github.com/moby/buildkit/util/pgpsign"
"github.com/pkg/errors"
"golang.org/x/crypto/ssh"
)
type sigType int
const (
sigTypePGP sigType = iota
sigTypeSSH
)
type Signature struct {
PGPSignature *packet.Signature
SSHSignature *sshsig.Signature
}
type VerifyPolicy struct {
RejectExpiredKeys bool
}
func VerifySignature(obj *gitobject.GitObject, pubKeyData []byte, policy *VerifyPolicy) error {
func VerifySignature(obj *gitobject.GitObject, pubKeyData []byte, policy *pgpsign.VerifyPolicy) error {
if len(obj.Signature) == 0 {
return errors.New("git object is not signed")
}
@@ -44,58 +28,20 @@ func VerifySignature(obj *gitobject.GitObject, pubKeyData []byte, policy *Verify
return err
}
if s.PGPSignature != nil {
return verifyPGPSignature(obj, s.PGPSignature, pubKeyData, policy)
return verifyPGPSignature(obj, pubKeyData, policy)
} else if s.SSHSignature != nil {
return verifySSHSignature(obj, s.SSHSignature, pubKeyData)
}
return errors.New("no valid signature found")
}
func verifyPGPSignature(obj *gitobject.GitObject, sig *packet.Signature, pubKeyData []byte, policy *VerifyPolicy) error {
sigBlock, _, err := parseSignatureBlock([]byte(obj.Signature))
if err != nil {
return err
}
ents, err := openpgp.ReadArmoredKeyRing(bytes.NewReader(pubKeyData))
if err != nil {
return errors.Wrap(err, "failed to read armored public key")
}
// add addition algorithm constraints
if err := checkAlgoPolicy(sig); err != nil {
return err
}
config := &packet.Config{}
if policy == nil || !policy.RejectExpiredKeys {
config.Time = func() time.Time {
return sig.CreationTime
}
}
signer, err := openpgp.CheckDetachedSignature(
ents,
func verifyPGPSignature(obj *gitobject.GitObject, pubKeyData []byte, policy *pgpsign.VerifyPolicy) error {
return pgpsign.VerifyArmoredDetachedSignature(
bytes.NewReader([]byte(obj.SignedData)),
bytes.NewReader(sigBlock),
config,
[]byte(obj.Signature),
pubKeyData,
policy,
)
if err != nil {
if sig.IssuerKeyId != nil {
return errors.Wrapf(err, "signature by %X", *sig.IssuerKeyId)
}
return err
}
if err := checkEntityUsableForSigning(signer, time.Now(), policy); err != nil {
return err
}
if err := checkCreationTime(sig.CreationTime, time.Now()); err != nil {
return err
}
return nil
}
func verifySSHSignature(obj *gitobject.GitObject, sig *sshsig.Signature, pubKeyData []byte) error {
@@ -125,130 +71,35 @@ func verifySSHSignature(obj *gitobject.GitObject, sig *sshsig.Signature, pubKeyD
return nil
}
func checkEntityUsableForSigning(e *openpgp.Entity, now time.Time, policy *VerifyPolicy) error {
if e == nil || e.PrimaryKey == nil {
return errors.New("nil entity or key")
}
// Expiry
if policy != nil && policy.RejectExpiredKeys {
if id := e.PrimaryIdentity(); id != nil && id.SelfSignature != nil {
if exp := id.SelfSignature.KeyLifetimeSecs; exp != nil && *exp > 0 {
expiry := e.PrimaryKey.CreationTime.Add(time.Duration(*exp) * time.Second)
if now.After(expiry) {
return errors.Errorf("key expired at %v", expiry)
}
}
}
}
// Revocation
if err := checkEntityRevocation(e); err != nil {
return err
}
// RSA bit length (optional)
if rsaPub, ok := e.PrimaryKey.PublicKey.(*rsa.PublicKey); ok {
if rsaPub.N.BitLen() < 2048 {
return errors.Errorf("RSA key too short: %d bits", rsaPub.N.BitLen())
}
}
return nil
}
func checkEntityRevocation(e *openpgp.Entity) error {
if e == nil {
return nil
}
for _, r := range e.Revocations {
if r == nil || r.SigType != packet.SigTypeKeyRevocation {
continue
}
if err := e.PrimaryKey.VerifyRevocationSignature(r); err != nil {
continue // ignore malformed or unverified revocations
}
if r.RevocationReasonText != "" {
return errors.Errorf("key revoked: %s", r.RevocationReasonText)
}
return errors.New("key revoked")
}
return nil
}
func parseSignatureBlock(data []byte) ([]byte, sigType, error) {
func parseSignatureBlock(data []byte) ([]byte, error) {
if strings.HasPrefix(string(data), "-----BEGIN SSH SIGNATURE-----") {
block, _ := pem.Decode(data)
if block == nil || block.Type != "SSH SIGNATURE" {
return nil, 0, errors.New("failed to decode ssh signature PEM block")
return nil, errors.New("failed to decode ssh signature PEM block")
}
return block.Bytes, sigTypeSSH, nil
} else if strings.HasPrefix(string(data), "-----BEGIN PGP SIGNATURE-----") {
block, err := armor.Decode(bytes.NewReader(data))
if err != nil {
return nil, 0, errors.Wrap(err, "failed to decode armored signature")
}
dt, err := io.ReadAll(block.Body)
if err != nil {
return nil, 0, errors.Wrap(err, "failed to read armored signature body")
}
return dt, sigTypePGP, nil
return block.Bytes, nil
}
return nil, 0, errors.Errorf("invalid signature format")
return nil, errors.Errorf("invalid signature format")
}
func ParseSignature(data []byte) (*Signature, error) {
sigBlock, typ, err := parseSignatureBlock(data)
if err != nil {
return nil, err
if strings.HasPrefix(string(data), "-----BEGIN PGP SIGNATURE-----") {
sig, _, err := pgpsign.ParseArmoredDetachedSignature(data)
if err != nil {
return nil, err
}
return &Signature{PGPSignature: sig}, nil
}
switch typ {
case sigTypePGP:
pr := packet.NewReader(bytes.NewReader(sigBlock))
for {
p, err := pr.Next()
if errors.Is(err, io.EOF) {
break
}
if err != nil {
return nil, errors.Wrap(err, "failed to read next packet")
}
sig, ok := p.(*packet.Signature)
if !ok {
continue
}
return &Signature{PGPSignature: sig}, nil
if strings.HasPrefix(string(data), "-----BEGIN SSH SIGNATURE-----") {
sigBlock, err := parseSignatureBlock(data)
if err != nil {
return nil, err
}
case sigTypeSSH:
sig, err := sshsig.ParseSignature(sigBlock)
if err != nil {
return nil, errors.Wrap(err, "failed to parse ssh signature")
}
return &Signature{SSHSignature: sig}, nil
}
return nil, errors.Errorf("no signature packet found")
}
func checkAlgoPolicy(sig *packet.Signature) error {
switch sig.Hash {
case crypto.SHA256, crypto.SHA384, crypto.SHA512:
// ok
default:
return errors.Errorf("rejecting weak/unknown hash: %v", sig.Hash)
}
// Pubkey policy
switch sig.PubKeyAlgo {
case packet.PubKeyAlgoEdDSA, packet.PubKeyAlgoECDSA, packet.PubKeyAlgoRSA, packet.PubKeyAlgoRSASignOnly:
default:
return errors.Errorf("rejecting unsupported pubkey algorithm: %v", sig.PubKeyAlgo)
}
return nil
}
func checkCreationTime(sigTime, now time.Time) error {
if sigTime.After(now.Add(5 * time.Minute)) {
return errors.Errorf("signature creation time is in the future: %v", sigTime)
}
return nil
return nil, errors.Errorf("invalid signature format")
}
+295
View File
@@ -0,0 +1,295 @@
package pgpsign
import (
"bytes"
"crypto"
"crypto/rsa"
"crypto/sha256"
"crypto/sha512"
"encoding/hex"
"io"
"time"
"github.com/ProtonMail/go-crypto/openpgp"
"github.com/ProtonMail/go-crypto/openpgp/armor"
"github.com/ProtonMail/go-crypto/openpgp/packet"
digest "github.com/opencontainers/go-digest"
"github.com/pkg/errors"
)
// VerifyPolicy defines validation policy for OpenPGP signature verification.
type VerifyPolicy struct {
RejectExpiredKeys bool
}
// ParseArmoredDetachedSignature parses a detached armored OpenPGP signature and
// returns the first signature packet and the decoded binary signature payload.
func ParseArmoredDetachedSignature(data []byte) (*packet.Signature, []byte, error) {
block, err := armor.Decode(bytes.NewReader(data))
if err != nil {
return nil, nil, errors.Wrap(err, "failed to decode armored signature")
}
sigBlock, err := io.ReadAll(block.Body)
if err != nil {
return nil, nil, errors.Wrap(err, "failed to read armored signature body")
}
pr := packet.NewReader(bytes.NewReader(sigBlock))
for {
p, err := pr.Next()
if errors.Is(err, io.EOF) {
break
}
if err != nil {
return nil, nil, errors.Wrap(err, "failed to read next packet")
}
sig, ok := p.(*packet.Signature)
if !ok {
continue
}
return sig, sigBlock, nil
}
return nil, nil, errors.New("no signature packet found")
}
// ReadAllArmoredKeyRings parses one or more concatenated armored OpenPGP key
// blocks and returns a combined entity list.
func ReadAllArmoredKeyRings(pubKeyData []byte) (openpgp.EntityList, error) {
var ents openpgp.EntityList
r := bytes.NewReader(pubKeyData)
for {
block, err := armor.Decode(r)
if errors.Is(err, io.EOF) {
break
}
if err != nil {
return nil, errors.Wrap(err, "failed to decode armored public key")
}
if block.Type != openpgp.PublicKeyType && block.Type != openpgp.PrivateKeyType {
return nil, errors.Errorf("expected public or private key block, got: %s", block.Type)
}
el, err := openpgp.ReadKeyRing(block.Body)
if err != nil {
return nil, errors.Wrap(err, "failed to read armored public key")
}
ents = append(ents, el...)
}
if len(ents) == 0 {
return nil, errors.New("failed to read armored public key: no armored data found")
}
return ents, nil
}
// VerifyArmoredDetachedSignature verifies an armored detached OpenPGP
// signature against signedData using one or more armored public key blocks.
func VerifyArmoredDetachedSignature(signedData io.Reader, signatureData, pubKeyData []byte, policy *VerifyPolicy) error {
sig, sigBlock, err := ParseArmoredDetachedSignature(signatureData)
if err != nil {
return err
}
ents, err := ReadAllArmoredKeyRings(pubKeyData)
if err != nil {
return err
}
if err := checkAlgoPolicy(sig); err != nil {
return err
}
config := &packet.Config{}
if policy == nil || !policy.RejectExpiredKeys {
config.Time = func() time.Time {
return sig.CreationTime
}
}
signer, err := openpgp.CheckDetachedSignature(
ents,
signedData,
bytes.NewReader(sigBlock),
config,
)
if err != nil {
if sig.IssuerKeyId != nil {
return errors.Wrapf(err, "signature by %X", *sig.IssuerKeyId)
}
return err
}
now := time.Now()
if err := checkEntityUsableForSigning(signer, now, policy); err != nil {
return err
}
if err := checkCreationTime(sig.CreationTime, now); err != nil {
return err
}
return nil
}
// VerifySignatureWithDigest verifies a parsed signature against a digest of
// the signed payload plus OpenPGP hash suffix (payload || suffix) using the
// provided keyring.
func VerifySignatureWithDigest(sig *packet.Signature, keyring openpgp.EntityList, dgst digest.Digest) error {
if sig == nil {
return errors.New("nil signature")
}
expectedAlgo, err := signatureDigestAlgorithm(sig.Hash)
if err != nil {
return err
}
if dgst.Algorithm() != expectedAlgo {
return errors.Errorf("digest algorithm mismatch: %s != %s", dgst.Algorithm(), expectedAlgo)
}
sum, err := hex.DecodeString(dgst.Encoded())
if err != nil {
return errors.Wrap(err, "invalid digest hex")
}
h := &staticHash{sum: sum, algo: sig.Hash}
if len(sum) != h.Size() {
return errors.Errorf("digest size mismatch: got %d, expected %d", len(sum), h.Size())
}
for _, e := range keyring {
if e.PrimaryKey != nil && e.PrimaryKey.VerifySignature(h, sig) == nil {
return nil
}
for _, sub := range e.Subkeys {
if sub.PublicKey != nil && sub.PublicKey.VerifySignature(h, sig) == nil {
return nil
}
}
}
return errors.New("failed to verify signature with checksum digest")
}
func signatureDigestAlgorithm(h crypto.Hash) (digest.Algorithm, error) {
switch h {
case crypto.SHA256:
return digest.SHA256, nil
case crypto.SHA384:
return digest.SHA384, nil
case crypto.SHA512:
return digest.SHA512, nil
default:
return "", errors.Errorf("unsupported signature hash algorithm %v", h)
}
}
type staticHash struct {
sum []byte
algo crypto.Hash
}
func (s *staticHash) Write(p []byte) (n int, err error) {
return len(p), nil
}
func (s *staticHash) Sum(b []byte) []byte {
return append(b, s.sum...)
}
func (s *staticHash) Reset() {}
func (s *staticHash) Size() int {
switch s.algo {
case crypto.SHA256:
return sha256.Size
case crypto.SHA384:
return sha512.Size384
case crypto.SHA512:
return sha512.Size
default:
return len(s.sum)
}
}
func (s *staticHash) BlockSize() int {
switch s.algo {
case crypto.SHA256:
return sha256.BlockSize
case crypto.SHA384, crypto.SHA512:
return sha512.BlockSize
default:
return 0
}
}
func checkAlgoPolicy(sig *packet.Signature) error {
switch sig.Hash {
case crypto.SHA256, crypto.SHA384, crypto.SHA512:
// ok
default:
return errors.Errorf("rejecting weak/unknown hash: %v", sig.Hash)
}
switch sig.PubKeyAlgo {
case packet.PubKeyAlgoEdDSA, packet.PubKeyAlgoECDSA, packet.PubKeyAlgoRSA, packet.PubKeyAlgoRSASignOnly:
default:
return errors.Errorf("rejecting unsupported pubkey algorithm: %v", sig.PubKeyAlgo)
}
return nil
}
func checkEntityUsableForSigning(e *openpgp.Entity, now time.Time, policy *VerifyPolicy) error {
if e == nil || e.PrimaryKey == nil {
return errors.New("nil entity or key")
}
if policy != nil && policy.RejectExpiredKeys {
if id := e.PrimaryIdentity(); id != nil && id.SelfSignature != nil {
if exp := id.SelfSignature.KeyLifetimeSecs; exp != nil && *exp > 0 {
expiry := e.PrimaryKey.CreationTime.Add(time.Duration(*exp) * time.Second)
if now.After(expiry) {
return errors.Errorf("key expired at %v", expiry)
}
}
}
}
if err := checkEntityRevocation(e); err != nil {
return err
}
if rsaPub, ok := e.PrimaryKey.PublicKey.(*rsa.PublicKey); ok {
if rsaPub.N.BitLen() < 2048 {
return errors.Errorf("RSA key too short: %d bits", rsaPub.N.BitLen())
}
}
return nil
}
func checkEntityRevocation(e *openpgp.Entity) error {
if e == nil {
return nil
}
for _, r := range e.Revocations {
if r == nil || r.SigType != packet.SigTypeKeyRevocation {
continue
}
if err := e.PrimaryKey.VerifyRevocationSignature(r); err != nil {
continue
}
if r.RevocationReasonText != "" {
return errors.Errorf("key revoked: %s", r.RevocationReasonText)
}
return errors.New("key revoked")
}
return nil
}
func checkCreationTime(sigTime, now time.Time) error {
if sigTime.After(now.Add(5 * time.Minute)) {
return errors.Errorf("signature creation time is in the future: %v", sigTime)
}
return nil
}
+1 -2
View File
@@ -1,2 +1 @@
bin
vendor
bin
+10
View File
@@ -0,0 +1,10 @@
.PHONY: all
all:
.PHONY: vendor
vendor:
$(eval $@_TMP_OUT := $(shell mktemp -d -t policy-helpers-output.XXXXXXXXXX))
docker buildx bake --set "*.output=type=local,dest=$($@_TMP_OUT)" vendor
rm -rf ./vendor
cp -R "$($@_TMP_OUT)"/* ./
rm -rf "$($@_TMP_OUT)"/*
+31 -2
View File
@@ -2,7 +2,7 @@ variable "ROOT_SIGNING_VERSION" {
type = string
# default = "8842feefbb65effea46ff4a0f2b6aad91e685fe9" # expired root
# default = "9d8b5c5e3bed603c80b57fcc316b7a1af688c57e" # expired timestamp
default = "b72505e865a7c68bd75e03272fa66512bcb41bb1"
default = "a72700d5c80d43a209d31325fee46facc6f0cf31"
description = "The git commit hash of sigstore/root-signing to use for embedded roots."
}
@@ -12,6 +12,12 @@ variable "DOCKER_HARDENED_IMAGES_KEYRING_VERSION" {
description = "The git branch or commit hash of docker/hardened-images-keyring to use for DHI verification."
}
target "_common" {
args = {
BUILDKIT_CONTEXT_KEEP_GIT_DIR = 1
}
}
target "tuf-root" {
target = "tuf-root"
output = [{
@@ -34,7 +40,7 @@ target "validate-tuf-root" {
}
group "validate-all" {
targets = ["lint", "lint-gopls", "validate-dockerfile", "validate-generated-files"]
targets = ["lint", "lint-gopls", "validate-vendor", "validate-dockerfile", "validate-generated-files"]
}
group "validate-generated-files" {
@@ -49,11 +55,19 @@ target "lint" {
}
}
target "validate-vendor" {
inherits = ["_common"]
dockerfile = "./hack/dockerfiles/vendor.Dockerfile"
target = "validate"
output = ["type=cacheonly"]
}
target "validate-dockerfile" {
matrix = {
dockerfile = [
"Dockerfile",
"./hack/dockerfiles/lint.Dockerfile",
"./hack/dockerfiles/vendor.Dockerfile"
]
}
name = "validate-dockerfile-${md5(dockerfile)}"
@@ -66,6 +80,21 @@ target "lint-gopls" {
target = "gopls-analyze"
}
target "vendor" {
inherits = ["_common"]
dockerfile = "./hack/dockerfiles/vendor.Dockerfile"
target = "update"
output = ["."]
}
target "mod-outdated" {
inherits = ["_common"]
dockerfile = "./hack/dockerfiles/vendor.Dockerfile"
target = "outdated"
no-cache-filter = ["outdated"]
output = ["type=cacheonly"]
}
target "binary" {
target = "binary"
platforms = [ "local" ]
+7 -11
View File
@@ -1,34 +1,30 @@
{
"signatures": [
{
"keyid": "6f260089d5923daf20166ca657c543af618346ab971884a99962b01988bbe0c3",
"sig": ""
},
{
"keyid": "e71a54d543835ba86adad9460379c7641fb8726d164ea766801a1c522aba7ea2",
"sig": "3045022100bbddd464f8066ceb88ba787375c12cd6330680e08c2910703e6538c71cc79ad202205190b06e4537fe961b3ef81fe68edcd0089c19f919afed423b9aafd700641153"
"sig": "3046022100e04c9706299be5d8c2b14fb50bcd5b9c241f10597153dfe22f943efe896b5150022100cfd7b9f06a5900784e312d02b8e336edbb3b2fab61ac14550b3112b4f9e33df4"
},
{
"keyid": "22f4caec6d8e6f9555af66b3d4c3cb06a3bb23fdc7e39c916c61f462e6f52b06",
"sig": "3044022069306cd5257f732a740c1afe60a8e433c5de58eafeadbe99c336c9c71d198cf802200d773953ae7dbc48d3e5bad9a6f64bafff196b7e2ad4a52a19519367d47dc042"
"sig": ""
},
{
"keyid": "61643838125b440b40db6942f5cb5a31c0dc04368316eb2aaa58b95904a58222",
"sig": "304402204d21a2ec80df66e61f6fe2912951dc47df836036f8c0ab10816d375e71dbf79e0220547adce1afdf04e6794efa203dd5264c6f7e0ef78e57fe934b0d26cb994eec76"
"sig": "3045022100cc308ae7d390fa782ee3376ddfaa929835016e86dad81f69e2de7ec1e174432e02205fb19906a31cce146c29624443c0d0c2f33ee80dac39d72114f939607cc22937"
},
{
"keyid": "a687e5bf4fab82b0ee58d46e05c9535145a2c9afb458f43d42b45ca0fdce2a70",
"sig": "3045022060826496557144eb1649893ed5f6f4ea54536feb0ca82f8b89ae641be39743e5022100ad7118b5e9d4837326206e412fc6da2999925d110328a7c166b06c624336c93f"
"sig": "304502203f8aff7a30e05a8c3d904b671ab1a6e4e8a6f508b7cfa0c780e72976bee7a227022100f64c9b765526f34d9ea16339cf238893e1c3368b4f0910a61a1af27dda01ebb9"
},
{
"keyid": "183e64f37670dc13ca0d28995a3053f3740954ddce44321a41e46534cf44e632",
"sig": "3046022100d8179439c2e73eb0c1733abee7faf832dcaea7263edcb4919891c3a247f05923022100e1a437e0797e803f9b72dc9d2d92155b0a2270c24efdd5f4b3a5d8f0b0f431a7"
"sig": "304502202363ca249aefa6d5f61c408a32cdd079b034a7888ddf2136dc4515ed4a728418022100b04eca42bc510ccbbf5d30783aaa936b1f137ca7a017ee9d90d3710432da0427"
}
],
"signed": {
"_type": "root",
"consistent_snapshot": true,
"expires": "2026-01-22T13:05:59Z",
"expires": "2026-06-22T13:27:01Z",
"keys": {
"0c87432c3bf09fd99189fdc32fa5eaedf4e4a5fac7bab73fa04a2e0fc64af6f5": {
"keyid_hash_algorithms": [
@@ -138,7 +134,7 @@
}
},
"spec_version": "1.0",
"version": 13,
"version": 14,
"x-tuf-on-ci-expiry-period": 197,
"x-tuf-on-ci-signing-period": 46
}
+4 -4
View File
@@ -2,15 +2,15 @@
"signatures": [
{
"keyid": "0c87432c3bf09fd99189fdc32fa5eaedf4e4a5fac7bab73fa04a2e0fc64af6f5",
"sig": "3044022043cdc6f2ee47ee7b4486ab92ce58424ef0b7b351a47853ea68316b67133a4a69022037c5cd433cc2cde76558c579c59a14dd9fc0bc85c496feaa17d90896cd4145fb"
"sig": "3046022100a42f44341870864aa7e4f94af642ed68e09890aa109d76947276e24f13c315f2022100c3efb5500a4b67cb03a0fe708db32d8f5f151aad4bbacfd6679437e8c5fa5f9f"
}
],
"signed": {
"_type": "snapshot",
"expires": "2035-10-08T16:46:31Z",
"expires": "2035-11-24T12:02:06Z",
"meta": {
"registry.npmjs.org.json": {
"version": 6
"version": 7
},
"rekor.json": {
"hashes": {
@@ -49,6 +49,6 @@
}
},
"spec_version": "1.0",
"version": 162
"version": 163
}
}
+4 -4
View File
@@ -2,18 +2,18 @@
"signatures": [
{
"keyid": "0c87432c3bf09fd99189fdc32fa5eaedf4e4a5fac7bab73fa04a2e0fc64af6f5",
"sig": "3046022100baf8a66a62531e9db32df4a1475099798cc6126add00193c8b641ed3dfb83b2c022100eedbc40511f1f72459b95188995917ad564992a2258436a96d27885c063b7de1"
"sig": "3046022100d7ef32458ba07441f1d840bae2d7cf5740ec01462499439e02f8ad9b5c53777f0221009c56763e60f8311a45c148f4276163c9f2b241ce0da65202f92f5de4ce2e4445"
}
],
"signed": {
"_type": "timestamp",
"expires": "2025-11-02T01:55:53Z",
"expires": "2026-02-12T13:42:54Z",
"meta": {
"snapshot.json": {
"version": 162
"version": 163
}
},
"spec_version": "1.0",
"version": 498
"version": 587
}
}