mirror of
https://github.com/containers/skopeo.git
synced 2025-09-17 15:30:38 +00:00
DO NOT MERGE: vendor UNMERGED c/image
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
This commit is contained in:
2
go.mod
2
go.mod
@@ -114,3 +114,5 @@ require (
|
||||
google.golang.org/grpc v1.72.2 // indirect
|
||||
google.golang.org/protobuf v1.36.6 // indirect
|
||||
)
|
||||
|
||||
replace github.com/containers/image/v5 => github.com/mtrmac/image/v5 v5.0.0-20250807201425-55d1eaf519bd
|
||||
|
4
go.sum
4
go.sum
@@ -39,8 +39,6 @@ github.com/containerd/typeurl/v2 v2.2.3 h1:yNA/94zxWdvYACdYO8zofhrTVuQY73fFU1y++
|
||||
github.com/containerd/typeurl/v2 v2.2.3/go.mod h1:95ljDnPfD3bAbDJRugOiShd/DlAAsxGtUBhJxIn7SCk=
|
||||
github.com/containers/common v0.64.1 h1:E8vSiL+B84/UCsyVSb70GoxY9cu+0bseLujm4EKF6GE=
|
||||
github.com/containers/common v0.64.1/go.mod h1:CtfQNHoCAZqWeXMwdShcsxmMJSeGRgKKMqAwRKmWrHE=
|
||||
github.com/containers/image/v5 v5.36.2-0.20250807195248-f8cef395fcde h1:uUtFXNTs4bGwB1h/iJPadA9xYo1jcHCQG5K3gWc9cWM=
|
||||
github.com/containers/image/v5 v5.36.2-0.20250807195248-f8cef395fcde/go.mod h1:x0jlG/5SvMUqUTD5H4f4ezuqU9E+PE6JnVfOJ+/vrPU=
|
||||
github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01 h1:Qzk5C6cYglewc+UyGf6lc8Mj2UaPTHy/iF2De0/77CA=
|
||||
github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01/go.mod h1:9rfv8iPl1ZP7aqh9YA68wnZv2NUDbXdcdPHVz0pFbPY=
|
||||
github.com/containers/ocicrypt v1.2.1 h1:0qIOTT9DoYwcKmxSt8QJt+VzMY18onl9jUXsxpVhSmM=
|
||||
@@ -204,6 +202,8 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
|
||||
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
||||
github.com/mtrmac/image/v5 v5.0.0-20250807201425-55d1eaf519bd h1:IpH02DMIjamb3rC3dKBtq/StZ+UysGfZoNs761um3Aw=
|
||||
github.com/mtrmac/image/v5 v5.0.0-20250807201425-55d1eaf519bd/go.mod h1:x0jlG/5SvMUqUTD5H4f4ezuqU9E+PE6JnVfOJ+/vrPU=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
github.com/onsi/ginkgo/v2 v2.23.4 h1:ktYTpKJAVZnDT4VjxSbiBenUjmlL/5QkBEocaWXiQus=
|
||||
|
12
vendor/github.com/containers/image/v5/signature/docker.go
generated
vendored
12
vendor/github.com/containers/image/v5/signature/docker.go
generated
vendored
@@ -5,7 +5,6 @@ package signature
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/containers/image/v5/docker/reference"
|
||||
@@ -64,15 +63,8 @@ func VerifyImageManifestSignatureUsingKeyIdentityList(unverifiedSignature, unver
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
var matchedKeyIdentity string
|
||||
sig, err := verifyAndExtractSignature(mech, unverifiedSignature, signatureAcceptanceRules{
|
||||
validateKeyIdentity: func(keyIdentity string) error {
|
||||
if !slices.Contains(expectedKeyIdentities, keyIdentity) {
|
||||
return internal.NewInvalidSignatureError(fmt.Sprintf("Signature by %s does not match expected fingerprints %v", keyIdentity, expectedKeyIdentities))
|
||||
}
|
||||
matchedKeyIdentity = keyIdentity
|
||||
return nil
|
||||
},
|
||||
sig, matchedKeyIdentity, err := verifyAndExtractSignature(mech, unverifiedSignature, signatureAcceptanceRules{
|
||||
acceptedKeyIdentities: expectedKeyIdentities,
|
||||
validateSignedDockerReference: func(signedDockerReference string) error {
|
||||
signedRef, err := reference.ParseNormalizedNamed(signedDockerReference)
|
||||
if err != nil {
|
||||
|
200
vendor/github.com/containers/image/v5/signature/internal/sequoia/gosequoia.c
generated
vendored
Normal file
200
vendor/github.com/containers/image/v5/signature/internal/sequoia/gosequoia.c
generated
vendored
Normal file
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* Copying and distribution of this file, with or without modification,
|
||||
* are permitted in any medium without royalty provided the copyright
|
||||
* notice and this notice are preserved. This file is offered as-is,
|
||||
* without any warranty.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "gosequoia.h"
|
||||
|
||||
#if defined(GO_SEQUOIA_ENABLE_DLOPEN) && GO_SEQUOIA_ENABLE_DLOPEN
|
||||
|
||||
#include <assert.h>
|
||||
#include <dlfcn.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* If SEQUOIA_SONAME is defined, dlopen handle can be automatically
|
||||
* set; otherwise, the caller needs to call
|
||||
* go_sequoia_ensure_library with soname determined at run time.
|
||||
*/
|
||||
#ifdef SEQUOIA_SONAME
|
||||
|
||||
static void
|
||||
ensure_library (void)
|
||||
{
|
||||
if (go_sequoia_ensure_library (SEQUOIA_SONAME, RTLD_LAZY | RTLD_LOCAL) < 0)
|
||||
abort ();
|
||||
}
|
||||
|
||||
#if defined(GO_SEQUOIA_ENABLE_PTHREAD) && GO_SEQUOIA_ENABLE_PTHREAD
|
||||
#include <pthread.h>
|
||||
|
||||
static pthread_once_t dlopen_once = PTHREAD_ONCE_INIT;
|
||||
|
||||
#define ENSURE_LIBRARY pthread_once(&dlopen_once, ensure_library)
|
||||
|
||||
#else /* GO_SEQUOIA_ENABLE_PTHREAD */
|
||||
|
||||
#define ENSURE_LIBRARY do { \
|
||||
if (!go_sequoia_dlhandle) \
|
||||
ensure_library(); \
|
||||
} while (0)
|
||||
|
||||
#endif /* !GO_SEQUOIA_ENABLE_PTHREAD */
|
||||
|
||||
#else /* SEQUOIA_SONAME */
|
||||
|
||||
#define ENSURE_LIBRARY do {} while (0)
|
||||
|
||||
#endif /* !SEQUOIA_SONAME */
|
||||
|
||||
static void *go_sequoia_dlhandle;
|
||||
|
||||
/* Define redirection symbols */
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-macros"
|
||||
|
||||
#if (2 <= __GNUC__ || (4 <= __clang_major__))
|
||||
#define FUNC(ret, name, args, cargs) \
|
||||
static __typeof__(name)(*go_sequoia_sym_##name);
|
||||
#else
|
||||
#define FUNC(ret, name, args, cargs) \
|
||||
static ret(*go_sequoia_sym_##name)args;
|
||||
#endif
|
||||
#define VOID_FUNC FUNC
|
||||
#include "gosequoiafuncs.h"
|
||||
#undef VOID_FUNC
|
||||
#undef FUNC
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
/* Define redirection wrapper functions */
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-macros"
|
||||
|
||||
#define FUNC(ret, name, args, cargs) \
|
||||
ret go_##name args \
|
||||
{ \
|
||||
ENSURE_LIBRARY; \
|
||||
assert (go_sequoia_sym_##name); \
|
||||
return go_sequoia_sym_##name cargs; \
|
||||
}
|
||||
#define VOID_FUNC(ret, name, args, cargs) \
|
||||
ret go_##name args \
|
||||
{ \
|
||||
ENSURE_LIBRARY; \
|
||||
assert (go_sequoia_sym_##name); \
|
||||
go_sequoia_sym_##name cargs; \
|
||||
}
|
||||
#include "gosequoiafuncs.h"
|
||||
#undef VOID_FUNC
|
||||
#undef FUNC
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
static int
|
||||
ensure_symbol (const char *name, void **symp)
|
||||
{
|
||||
if (!*symp)
|
||||
{
|
||||
void *sym = dlsym (go_sequoia_dlhandle, name);
|
||||
if (!sym)
|
||||
return -EINVAL;
|
||||
*symp = sym;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
go_sequoia_ensure_library (const char *soname, int flags)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (!go_sequoia_dlhandle)
|
||||
{
|
||||
go_sequoia_dlhandle = dlopen (soname, flags);
|
||||
if (!go_sequoia_dlhandle)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#define ENSURE_SYMBOL(name) \
|
||||
ensure_symbol(#name, (void **)&go_sequoia_sym_##name)
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-macros"
|
||||
|
||||
#define FUNC(ret, name, args, cargs) \
|
||||
err = ENSURE_SYMBOL(name); \
|
||||
if (err < 0) \
|
||||
{ \
|
||||
dlclose (go_sequoia_dlhandle); \
|
||||
go_sequoia_dlhandle = NULL; \
|
||||
return err; \
|
||||
}
|
||||
#define VOID_FUNC FUNC
|
||||
#include "gosequoiafuncs.h"
|
||||
#undef VOID_FUNC
|
||||
#undef FUNC
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
#undef ENSURE_SYMBOL
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
go_sequoia_unload_library (void)
|
||||
{
|
||||
if (go_sequoia_dlhandle)
|
||||
{
|
||||
dlclose (go_sequoia_dlhandle);
|
||||
go_sequoia_dlhandle = NULL;
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-macros"
|
||||
|
||||
#define FUNC(ret, name, args, cargs) \
|
||||
go_sequoia_sym_##name = NULL;
|
||||
#define VOID_FUNC FUNC
|
||||
#include "gosequoiafuncs.h"
|
||||
#undef VOID_FUNC
|
||||
#undef FUNC
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
}
|
||||
|
||||
unsigned
|
||||
go_sequoia_is_usable (void)
|
||||
{
|
||||
return go_sequoia_dlhandle != NULL;
|
||||
}
|
||||
|
||||
#else /* GO_SEQUOIA_ENABLE_DLOPEN */
|
||||
|
||||
int
|
||||
go_sequoia_ensure_library (const char *soname, int flags)
|
||||
{
|
||||
(void) soname;
|
||||
(void) flags;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
go_sequoia_unload_library (void)
|
||||
{
|
||||
}
|
||||
|
||||
unsigned
|
||||
go_sequoia_is_usable (void)
|
||||
{
|
||||
/* The library is linked at build time, thus always usable */
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif /* !GO_SEQUOIA_ENABLE_DLOPEN */
|
54
vendor/github.com/containers/image/v5/signature/internal/sequoia/gosequoia.h
generated
vendored
Normal file
54
vendor/github.com/containers/image/v5/signature/internal/sequoia/gosequoia.h
generated
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copying and distribution of this file, with or without modification,
|
||||
* are permitted in any medium without royalty provided the copyright
|
||||
* notice and this notice are preserved. This file is offered as-is,
|
||||
* without any warranty.
|
||||
*/
|
||||
|
||||
#ifndef GO_SEQUOIA_H_
|
||||
#define GO_SEQUOIA_H_
|
||||
|
||||
#include <sequoia.h>
|
||||
|
||||
#if defined(GO_SEQUOIA_ENABLE_DLOPEN) && GO_SEQUOIA_ENABLE_DLOPEN
|
||||
|
||||
#define FUNC(ret, name, args, cargs) \
|
||||
ret go_##name args;
|
||||
#define VOID_FUNC FUNC
|
||||
#include "gosequoiafuncs.h"
|
||||
#undef VOID_FUNC
|
||||
#undef FUNC
|
||||
|
||||
#define GO_SEQUOIA_FUNC(name) go_##name
|
||||
|
||||
#else
|
||||
|
||||
#define GO_SEQUOIA_FUNC(name) name
|
||||
|
||||
#endif /* GO_SEQUOIA_ENABLE_DLOPEN */
|
||||
|
||||
/* Ensure SONAME to be loaded with dlopen FLAGS, and all the necessary
|
||||
* symbols are resolved.
|
||||
*
|
||||
* Returns 0 on success; negative error code otherwise.
|
||||
*
|
||||
* Note that this function is NOT thread-safe; when calling it from
|
||||
* multi-threaded programs, protect it with a locking mechanism.
|
||||
*/
|
||||
int go_sequoia_ensure_library (const char *soname, int flags);
|
||||
|
||||
/* Unload library and reset symbols.
|
||||
*
|
||||
* Note that this function is NOT thread-safe; when calling it from
|
||||
* multi-threaded programs, protect it with a locking mechanism.
|
||||
*/
|
||||
void go_sequoia_unload_library (void);
|
||||
|
||||
/* Return 1 if the library is loaded and usable.
|
||||
*
|
||||
* Note that this function is NOT thread-safe; when calling it from
|
||||
* multi-threaded programs, protect it with a locking mechanism.
|
||||
*/
|
||||
unsigned go_sequoia_is_usable (void);
|
||||
|
||||
#endif /* GO_SEQUOIA_H_ */
|
21
vendor/github.com/containers/image/v5/signature/internal/sequoia/gosequoiafuncs.h
generated
vendored
Normal file
21
vendor/github.com/containers/image/v5/signature/internal/sequoia/gosequoiafuncs.h
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* This file was automatically generated from sequoia.h,
|
||||
* which is covered by the following license:
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
VOID_FUNC(void, sequoia_error_free, (struct SequoiaError *err_ptr), (err_ptr))
|
||||
FUNC(struct SequoiaMechanism *, sequoia_mechanism_new_from_directory, (const char *dir_ptr, struct SequoiaError **err_ptr), (dir_ptr, err_ptr))
|
||||
FUNC(struct SequoiaMechanism *, sequoia_mechanism_new_ephemeral, (struct SequoiaError **err_ptr), (err_ptr))
|
||||
VOID_FUNC(void, sequoia_mechanism_free, (struct SequoiaMechanism *mechanism_ptr), (mechanism_ptr))
|
||||
VOID_FUNC(void, sequoia_signature_free, (struct SequoiaSignature *signature_ptr), (signature_ptr))
|
||||
FUNC(const uint8_t *, sequoia_signature_get_data, (const struct SequoiaSignature *signature_ptr, size_t *data_len), (signature_ptr, data_len))
|
||||
VOID_FUNC(void, sequoia_verification_result_free, (struct SequoiaVerificationResult *result_ptr), (result_ptr))
|
||||
FUNC(const uint8_t *, sequoia_verification_result_get_content, (const struct SequoiaVerificationResult *result_ptr, size_t *data_len), (result_ptr, data_len))
|
||||
FUNC(const char *, sequoia_verification_result_get_signer, (const struct SequoiaVerificationResult *result_ptr), (result_ptr))
|
||||
FUNC(struct SequoiaSignature *, sequoia_sign, (struct SequoiaMechanism *mechanism_ptr, const char *key_handle_ptr, const char *password_ptr, const uint8_t *data_ptr, size_t data_len, struct SequoiaError **err_ptr), (mechanism_ptr, key_handle_ptr, password_ptr, data_ptr, data_len, err_ptr))
|
||||
FUNC(struct SequoiaVerificationResult *, sequoia_verify, (struct SequoiaMechanism *mechanism_ptr, const uint8_t *signature_ptr, size_t signature_len, struct SequoiaError **err_ptr), (mechanism_ptr, signature_ptr, signature_len, err_ptr))
|
||||
VOID_FUNC(void, sequoia_import_result_free, (struct SequoiaImportResult *result_ptr), (result_ptr))
|
||||
FUNC(size_t, sequoia_import_result_get_count, (const struct SequoiaImportResult *result_ptr), (result_ptr))
|
||||
FUNC(const char *, sequoia_import_result_get_content, (const struct SequoiaImportResult *result_ptr, size_t index, struct SequoiaError **err_ptr), (result_ptr, index, err_ptr))
|
||||
FUNC(struct SequoiaImportResult *, sequoia_import_keys, (struct SequoiaMechanism *mechanism_ptr, const uint8_t *blob_ptr, size_t blob_len, struct SequoiaError **err_ptr), (mechanism_ptr, blob_ptr, blob_len, err_ptr))
|
||||
FUNC(int, sequoia_set_logger_consumer, (void (*consumer)(enum SequoiaLogLevel, const char *), struct SequoiaError **err_ptr), (consumer, err_ptr))
|
223
vendor/github.com/containers/image/v5/signature/internal/sequoia/sequoia.go
generated
vendored
Normal file
223
vendor/github.com/containers/image/v5/signature/internal/sequoia/sequoia.go
generated
vendored
Normal file
@@ -0,0 +1,223 @@
|
||||
//go:build containers_image_sequoia
|
||||
|
||||
package sequoia
|
||||
|
||||
// #cgo CFLAGS: -I. -DGO_SEQUOIA_ENABLE_DLOPEN=1
|
||||
// #include "gosequoia.h"
|
||||
// #include <dlfcn.h>
|
||||
// #include <limits.h>
|
||||
// typedef void (*sequoia_logger_consumer_t) (enum SequoiaLogLevel level, char *message);
|
||||
// extern void sequoia_logrus_logger (enum SequoiaLogLevel level, char *message);
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"sync"
|
||||
"unsafe"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// sequoiaLibraryDir is the path to the directory where libpodman_sequoia is installed,
|
||||
// if it is not in the platform’s default library path.
|
||||
// You can override this at build time with
|
||||
// -ldflags '-X github.com/containers/image/v5/signature/sequoia.sequoiaLibraryDir=$your_path'
|
||||
var sequoiaLibraryDir = ""
|
||||
|
||||
type SigningMechanism struct {
|
||||
mechanism *C.SequoiaMechanism
|
||||
}
|
||||
|
||||
// NewMechanismFromDirectory initializes a mechanism using (user-managed) Sequoia state
|
||||
// in dir, which can be "" to indicate the default (using $SEQUOIA_HOME or the default home directory location).
|
||||
func NewMechanismFromDirectory(
|
||||
dir string,
|
||||
) (*SigningMechanism, error) {
|
||||
var cerr *C.SequoiaError
|
||||
var cDir *C.char
|
||||
if dir != "" {
|
||||
cDir = C.CString(dir)
|
||||
defer C.free(unsafe.Pointer(cDir))
|
||||
}
|
||||
cMechanism := C.go_sequoia_mechanism_new_from_directory(cDir, &cerr)
|
||||
if cMechanism == nil {
|
||||
defer C.go_sequoia_error_free(cerr)
|
||||
return nil, errors.New(C.GoString(cerr.message))
|
||||
}
|
||||
return &SigningMechanism{
|
||||
mechanism: cMechanism,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func NewEphemeralMechanism() (*SigningMechanism, error) {
|
||||
var cerr *C.SequoiaError
|
||||
cMechanism := C.go_sequoia_mechanism_new_ephemeral(&cerr)
|
||||
if cMechanism == nil {
|
||||
defer C.go_sequoia_error_free(cerr)
|
||||
return nil, errors.New(C.GoString(cerr.message))
|
||||
}
|
||||
return &SigningMechanism{
|
||||
mechanism: cMechanism,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (m *SigningMechanism) SignWithPassphrase(
|
||||
input []byte,
|
||||
keyIdentity string,
|
||||
passphrase string,
|
||||
) ([]byte, error) {
|
||||
var cerr *C.SequoiaError
|
||||
var cPassphrase *C.char
|
||||
if passphrase == "" {
|
||||
cPassphrase = nil
|
||||
} else {
|
||||
cPassphrase = C.CString(passphrase)
|
||||
defer C.free(unsafe.Pointer(cPassphrase))
|
||||
}
|
||||
cKeyIdentity := C.CString(keyIdentity)
|
||||
defer C.free(unsafe.Pointer(cKeyIdentity))
|
||||
sig := C.go_sequoia_sign(
|
||||
m.mechanism,
|
||||
cKeyIdentity,
|
||||
cPassphrase,
|
||||
(*C.uchar)(unsafe.Pointer(unsafe.SliceData(input))),
|
||||
C.size_t(len(input)),
|
||||
&cerr,
|
||||
)
|
||||
if sig == nil {
|
||||
defer C.go_sequoia_error_free(cerr)
|
||||
return nil, errors.New(C.GoString(cerr.message))
|
||||
}
|
||||
defer C.go_sequoia_signature_free(sig)
|
||||
var size C.size_t
|
||||
cData := C.go_sequoia_signature_get_data(sig, &size)
|
||||
if size > C.size_t(C.INT_MAX) {
|
||||
return nil, errors.New("overflow") // Coverage: This should not reasonably happen, and we don’t want to generate gigabytes of input to test this.
|
||||
}
|
||||
return C.GoBytes(unsafe.Pointer(cData), C.int(size)), nil
|
||||
}
|
||||
|
||||
func (m *SigningMechanism) Sign(
|
||||
input []byte,
|
||||
keyIdentity string,
|
||||
) ([]byte, error) {
|
||||
return m.SignWithPassphrase(input, keyIdentity, "")
|
||||
}
|
||||
|
||||
func (m *SigningMechanism) Verify(
|
||||
unverifiedSignature []byte,
|
||||
) (contents []byte, keyIdentity string, err error) {
|
||||
var cerr *C.SequoiaError
|
||||
result := C.go_sequoia_verify(
|
||||
m.mechanism,
|
||||
(*C.uchar)(unsafe.Pointer(unsafe.SliceData(unverifiedSignature))),
|
||||
C.size_t(len(unverifiedSignature)),
|
||||
&cerr,
|
||||
)
|
||||
if result == nil {
|
||||
defer C.go_sequoia_error_free(cerr)
|
||||
return nil, "", errors.New(C.GoString(cerr.message))
|
||||
}
|
||||
defer C.go_sequoia_verification_result_free(result)
|
||||
var size C.size_t
|
||||
cContent := C.go_sequoia_verification_result_get_content(result, &size)
|
||||
if size > C.size_t(C.INT_MAX) {
|
||||
return nil, "", errors.New("overflow") // Coverage: This should not reasonably happen, and we don’t want to generate gigabytes of input to test this.
|
||||
}
|
||||
contents = C.GoBytes(unsafe.Pointer(cContent), C.int(size))
|
||||
cSigner := C.go_sequoia_verification_result_get_signer(result)
|
||||
keyIdentity = C.GoString(cSigner)
|
||||
return contents, keyIdentity, nil
|
||||
}
|
||||
|
||||
func (m *SigningMechanism) ImportKeys(blob []byte) ([]string, error) {
|
||||
var cerr *C.SequoiaError
|
||||
result := C.go_sequoia_import_keys(
|
||||
m.mechanism,
|
||||
(*C.uchar)(unsafe.Pointer(unsafe.SliceData(blob))),
|
||||
C.size_t(len(blob)),
|
||||
&cerr,
|
||||
)
|
||||
if result == nil {
|
||||
defer C.go_sequoia_error_free(cerr)
|
||||
return nil, errors.New(C.GoString(cerr.message))
|
||||
}
|
||||
defer C.go_sequoia_import_result_free(result)
|
||||
|
||||
keyIdentities := []string{}
|
||||
count := C.go_sequoia_import_result_get_count(result)
|
||||
for i := C.size_t(0); i < count; i++ {
|
||||
var cerr *C.SequoiaError
|
||||
cKeyIdentity := C.go_sequoia_import_result_get_content(result, i, &cerr)
|
||||
if cerr != nil {
|
||||
defer C.go_sequoia_error_free(cerr) // Coverage: this can fail only if i is out of range.
|
||||
return nil, errors.New(C.GoString(cerr.message))
|
||||
}
|
||||
keyIdentities = append(keyIdentities, C.GoString(cKeyIdentity))
|
||||
}
|
||||
|
||||
return keyIdentities, nil
|
||||
}
|
||||
|
||||
func (m *SigningMechanism) Close() error {
|
||||
C.go_sequoia_mechanism_free(m.mechanism)
|
||||
return nil
|
||||
}
|
||||
|
||||
//export sequoia_logrus_logger
|
||||
func sequoia_logrus_logger(level C.enum_SequoiaLogLevel, message *C.char) {
|
||||
var logrusLevel logrus.Level
|
||||
switch level { // Coverage: We are not in control of whether / how the Rust code chooses to log things.
|
||||
case C.SEQUOIA_LOG_LEVEL_ERROR:
|
||||
logrusLevel = logrus.ErrorLevel
|
||||
case C.SEQUOIA_LOG_LEVEL_WARN:
|
||||
logrusLevel = logrus.WarnLevel
|
||||
case C.SEQUOIA_LOG_LEVEL_INFO:
|
||||
logrusLevel = logrus.InfoLevel
|
||||
case C.SEQUOIA_LOG_LEVEL_DEBUG:
|
||||
logrusLevel = logrus.DebugLevel
|
||||
case C.SEQUOIA_LOG_LEVEL_TRACE:
|
||||
logrusLevel = logrus.TraceLevel
|
||||
case C.SEQUOIA_LOG_LEVEL_UNKNOWN:
|
||||
fallthrough
|
||||
default:
|
||||
logrusLevel = logrus.ErrorLevel // Should never happen
|
||||
}
|
||||
logrus.StandardLogger().Log(logrusLevel, C.GoString(message))
|
||||
}
|
||||
|
||||
// initOnce should only be called by Init.
|
||||
func initOnce() error {
|
||||
var soName string
|
||||
switch runtime.GOOS {
|
||||
case "linux":
|
||||
soName = "libpodman_sequoia.so.0"
|
||||
case "darwin":
|
||||
soName = "libpodman_sequoia.dylib"
|
||||
default:
|
||||
return fmt.Errorf("Unhandled OS %q in sequoia initialization", runtime.GOOS) // Coverage: This is ~by definition not reached in tests.
|
||||
}
|
||||
if sequoiaLibraryDir != "" {
|
||||
soName = filepath.Join(sequoiaLibraryDir, soName)
|
||||
}
|
||||
cSOName := C.CString(soName)
|
||||
defer C.free(unsafe.Pointer(cSOName))
|
||||
if C.go_sequoia_ensure_library(cSOName,
|
||||
C.RTLD_NOW|C.RTLD_GLOBAL) < 0 {
|
||||
return fmt.Errorf("unable to load %q", soName) // Coverage: This is impractical to test in-process, with the static go_sequoia_dlhandle.
|
||||
}
|
||||
|
||||
var cerr *C.SequoiaError
|
||||
if C.go_sequoia_set_logger_consumer(C.sequoia_logger_consumer_t(C.sequoia_logrus_logger), &cerr) != 0 {
|
||||
defer C.go_sequoia_error_free(cerr) // Coverage: This is impractical to test in-process, with the static go_sequoia_dlhandle.
|
||||
return fmt.Errorf("initializing logging: %s", C.GoString(cerr.message))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Init ensures the libpodman_sequoia library is available.
|
||||
// It is safe to call from arbitrary goroutines.
|
||||
var Init = sync.OnceValue(initOnce)
|
85
vendor/github.com/containers/image/v5/signature/internal/sequoia/sequoia.h
generated
vendored
Normal file
85
vendor/github.com/containers/image/v5/signature/internal/sequoia/sequoia.h
generated
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef enum SequoiaErrorKind {
|
||||
SEQUOIA_ERROR_KIND_UNKNOWN,
|
||||
SEQUOIA_ERROR_KIND_INVALID_ARGUMENT,
|
||||
SEQUOIA_ERROR_KIND_IO_ERROR,
|
||||
} SequoiaErrorKind;
|
||||
|
||||
typedef enum SequoiaLogLevel {
|
||||
SEQUOIA_LOG_LEVEL_UNKNOWN,
|
||||
SEQUOIA_LOG_LEVEL_ERROR,
|
||||
SEQUOIA_LOG_LEVEL_WARN,
|
||||
SEQUOIA_LOG_LEVEL_INFO,
|
||||
SEQUOIA_LOG_LEVEL_DEBUG,
|
||||
SEQUOIA_LOG_LEVEL_TRACE,
|
||||
} SequoiaLogLevel;
|
||||
|
||||
typedef struct SequoiaImportResult SequoiaImportResult;
|
||||
|
||||
typedef struct SequoiaMechanism SequoiaMechanism;
|
||||
|
||||
typedef struct SequoiaSignature SequoiaSignature;
|
||||
|
||||
typedef struct SequoiaVerificationResult SequoiaVerificationResult;
|
||||
|
||||
typedef struct SequoiaError {
|
||||
enum SequoiaErrorKind kind;
|
||||
char *message;
|
||||
} SequoiaError;
|
||||
|
||||
void sequoia_error_free(struct SequoiaError *err_ptr);
|
||||
|
||||
struct SequoiaMechanism *sequoia_mechanism_new_from_directory(const char *dir_ptr,
|
||||
struct SequoiaError **err_ptr);
|
||||
|
||||
struct SequoiaMechanism *sequoia_mechanism_new_ephemeral(struct SequoiaError **err_ptr);
|
||||
|
||||
void sequoia_mechanism_free(struct SequoiaMechanism *mechanism_ptr);
|
||||
|
||||
void sequoia_signature_free(struct SequoiaSignature *signature_ptr);
|
||||
|
||||
const uint8_t *sequoia_signature_get_data(const struct SequoiaSignature *signature_ptr,
|
||||
size_t *data_len);
|
||||
|
||||
void sequoia_verification_result_free(struct SequoiaVerificationResult *result_ptr);
|
||||
|
||||
const uint8_t *sequoia_verification_result_get_content(const struct SequoiaVerificationResult *result_ptr,
|
||||
size_t *data_len);
|
||||
|
||||
const char *sequoia_verification_result_get_signer(const struct SequoiaVerificationResult *result_ptr);
|
||||
|
||||
struct SequoiaSignature *sequoia_sign(struct SequoiaMechanism *mechanism_ptr,
|
||||
const char *key_handle_ptr,
|
||||
const char *password_ptr,
|
||||
const uint8_t *data_ptr,
|
||||
size_t data_len,
|
||||
struct SequoiaError **err_ptr);
|
||||
|
||||
struct SequoiaVerificationResult *sequoia_verify(struct SequoiaMechanism *mechanism_ptr,
|
||||
const uint8_t *signature_ptr,
|
||||
size_t signature_len,
|
||||
struct SequoiaError **err_ptr);
|
||||
|
||||
void sequoia_import_result_free(struct SequoiaImportResult *result_ptr);
|
||||
|
||||
size_t sequoia_import_result_get_count(const struct SequoiaImportResult *result_ptr);
|
||||
|
||||
const char *sequoia_import_result_get_content(const struct SequoiaImportResult *result_ptr,
|
||||
size_t index,
|
||||
struct SequoiaError **err_ptr);
|
||||
|
||||
struct SequoiaImportResult *sequoia_import_keys(struct SequoiaMechanism *mechanism_ptr,
|
||||
const uint8_t *blob_ptr,
|
||||
size_t blob_len,
|
||||
struct SequoiaError **err_ptr);
|
||||
|
||||
int sequoia_set_logger_consumer(void (*consumer)(enum SequoiaLogLevel level, const char *message),
|
||||
struct SequoiaError **err_ptr);
|
15
vendor/github.com/containers/image/v5/signature/mechanism.go
generated
vendored
15
vendor/github.com/containers/image/v5/signature/mechanism.go
generated
vendored
@@ -27,7 +27,10 @@ type SigningMechanism interface {
|
||||
// Sign creates a (non-detached) signature of input using keyIdentity.
|
||||
// Fails with a SigningNotSupportedError if the mechanism does not support signing.
|
||||
Sign(input []byte, keyIdentity string) ([]byte, error)
|
||||
// Verify parses unverifiedSignature and returns the content and the signer's identity
|
||||
// Verify parses unverifiedSignature and returns the content and the signer's identity.
|
||||
// For mechanisms created using NewEphemeralGPGSigningMechanism, the returned key identity
|
||||
// is expected to be one of the values returned by NewEphemeralGPGSigningMechanism,
|
||||
// or the mechanism should implement signingMechanismWithVerificationIdentityLookup.
|
||||
Verify(unverifiedSignature []byte) (contents []byte, keyIdentity string, err error)
|
||||
// UntrustedSignatureContents returns UNTRUSTED contents of the signature WITHOUT ANY VERIFICATION,
|
||||
// along with a short identifier of the key used for signing.
|
||||
@@ -46,6 +49,16 @@ type signingMechanismWithPassphrase interface {
|
||||
SignWithPassphrase(input []byte, keyIdentity string, passphrase string) ([]byte, error)
|
||||
}
|
||||
|
||||
// signingMechanismWithVerificationIdentityLookup is an internal extension of SigningMechanism.
|
||||
type signingMechanismWithVerificationIdentityLookup interface {
|
||||
SigningMechanism
|
||||
// keyIdentityForVerificationKeyIdentity re-checks the key identity returned by Verify
|
||||
// if it doesn't match an identity returned by NewEphemeralGPGSigningMechanism, trying to match it.
|
||||
// (To be more specific, for mechanisms which return a subkey fingerprint from Verify,
|
||||
// this converts the subkey fingerprint into the corresponding primary key fingerprint.)
|
||||
keyIdentityForVerificationKeyIdentity(keyIdentity string) (string, error)
|
||||
}
|
||||
|
||||
// SigningNotSupportedError is returned when trying to sign using a mechanism which does not support that.
|
||||
type SigningNotSupportedError string
|
||||
|
||||
|
99
vendor/github.com/containers/image/v5/signature/mechanism_gpgme.go
generated
vendored
99
vendor/github.com/containers/image/v5/signature/mechanism_gpgme.go
generated
vendored
@@ -2,6 +2,9 @@
|
||||
|
||||
package signature
|
||||
|
||||
// This is shared by mechanism_gpgme_only.go and mechanism_sequoia.go; in both situations
|
||||
// newGPGSigningMechanismInDirectory is implemented using GPGME.
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
@@ -18,6 +21,16 @@ type gpgmeSigningMechanism struct {
|
||||
ephemeralDir string // If not "", a directory to be removed on Close()
|
||||
}
|
||||
|
||||
// newGPGMESigningMechanism returns a new GPG/OpenPGP signing mechanism for ctx.
|
||||
// The caller must call .Close() on the returned SigningMechanism; if ephemeralDir is set,
|
||||
// the .Close() call will remove its contents.
|
||||
func newGPGMESigningMechanism(ctx *gpgme.Context, ephemeralDir string) signingMechanismWithPassphrase {
|
||||
return &gpgmeSigningMechanism{
|
||||
ctx: ctx,
|
||||
ephemeralDir: ephemeralDir,
|
||||
}
|
||||
}
|
||||
|
||||
// newGPGSigningMechanismInDirectory returns a new GPG/OpenPGP signing mechanism, using optionalDir if not empty.
|
||||
// The caller must call .Close() on the returned SigningMechanism.
|
||||
func newGPGSigningMechanismInDirectory(optionalDir string) (signingMechanismWithPassphrase, error) {
|
||||
@@ -25,46 +38,7 @@ func newGPGSigningMechanismInDirectory(optionalDir string) (signingMechanismWith
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &gpgmeSigningMechanism{
|
||||
ctx: ctx,
|
||||
ephemeralDir: "",
|
||||
}, nil
|
||||
}
|
||||
|
||||
// newEphemeralGPGSigningMechanism returns a new GPG/OpenPGP signing mechanism which
|
||||
// recognizes _only_ public keys from the supplied blobs, and returns the identities
|
||||
// of these keys.
|
||||
// The caller must call .Close() on the returned SigningMechanism.
|
||||
func newEphemeralGPGSigningMechanism(blobs [][]byte) (signingMechanismWithPassphrase, []string, error) {
|
||||
dir, err := os.MkdirTemp("", "containers-ephemeral-gpg-")
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
removeDir := true
|
||||
defer func() {
|
||||
if removeDir {
|
||||
os.RemoveAll(dir)
|
||||
}
|
||||
}()
|
||||
ctx, err := newGPGMEContext(dir)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
mech := &gpgmeSigningMechanism{
|
||||
ctx: ctx,
|
||||
ephemeralDir: dir,
|
||||
}
|
||||
keyIdentities := []string{}
|
||||
for _, blob := range blobs {
|
||||
ki, err := mech.importKeysFromBytes(blob)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
keyIdentities = append(keyIdentities, ki...)
|
||||
}
|
||||
|
||||
removeDir = false
|
||||
return mech, keyIdentities, nil
|
||||
return newGPGMESigningMechanism(ctx, ""), nil
|
||||
}
|
||||
|
||||
// newGPGMEContext returns a new *gpgme.Context, using optionalDir if not empty.
|
||||
@@ -94,28 +68,6 @@ func (m *gpgmeSigningMechanism) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// importKeysFromBytes imports public keys from the supplied blob and returns their identities.
|
||||
// The blob is assumed to have an appropriate format (the caller is expected to know which one).
|
||||
// NOTE: This may modify long-term state (e.g. key storage in a directory underlying the mechanism);
|
||||
// but we do not make this public, it can only be used through newEphemeralGPGSigningMechanism.
|
||||
func (m *gpgmeSigningMechanism) importKeysFromBytes(blob []byte) ([]string, error) {
|
||||
inputData, err := gpgme.NewDataBytes(blob)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, err := m.ctx.Import(inputData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
keyIdentities := []string{}
|
||||
for _, i := range res.Imports {
|
||||
if i.Result == nil {
|
||||
keyIdentities = append(keyIdentities, i.Fingerprint)
|
||||
}
|
||||
}
|
||||
return keyIdentities, nil
|
||||
}
|
||||
|
||||
// SupportsSigning returns nil if the mechanism supports signing, or a SigningNotSupportedError.
|
||||
func (m *gpgmeSigningMechanism) SupportsSigning() error {
|
||||
return nil
|
||||
@@ -169,7 +121,10 @@ func (m *gpgmeSigningMechanism) Sign(input []byte, keyIdentity string) ([]byte,
|
||||
return m.SignWithPassphrase(input, keyIdentity, "")
|
||||
}
|
||||
|
||||
// Verify parses unverifiedSignature and returns the content and the signer's identity
|
||||
// Verify parses unverifiedSignature and returns the content and the signer's identity.
|
||||
// For mechanisms created using NewEphemeralGPGSigningMechanism, the returned key identity
|
||||
// is expected to be one of the values returned by NewEphemeralGPGSigningMechanism,
|
||||
// or the mechanism should implement signingMechanismWithVerificationIdentityLookup.
|
||||
func (m *gpgmeSigningMechanism) Verify(unverifiedSignature []byte) (contents []byte, keyIdentity string, err error) {
|
||||
signedBuffer := bytes.Buffer{}
|
||||
signedData, err := gpgme.NewDataWriter(&signedBuffer)
|
||||
@@ -196,6 +151,24 @@ func (m *gpgmeSigningMechanism) Verify(unverifiedSignature []byte) (contents []b
|
||||
return signedBuffer.Bytes(), sig.Fingerprint, nil
|
||||
}
|
||||
|
||||
// keyIdentityForVerificationKeyIdentity re-checks the key identity returned by Verify
|
||||
// if it doesn't match an identity returned by NewEphemeralGPGSigningMechanism, trying to match it.
|
||||
// (To be more specific, for mechanisms which return a subkey fingerprint from Verify,
|
||||
// this converts the subkey fingerprint into the corresponding primary key fingerprint.)
|
||||
func (m *gpgmeSigningMechanism) keyIdentityForVerificationKeyIdentity(keyIdentity string) (string, error) {
|
||||
// In theory, if keyIdentity refers to a subkey, the same subkey could be attached to different primary keys;
|
||||
// in that case, GetKey fails with “ambiguous name”.
|
||||
// We _could_ handle that, by using KeyList* (GetKey is internally just a helper for KeyList*), but sharing
|
||||
// a subkey that way is very unexpected, so, for now, prefer the much simpler implementation.
|
||||
key, err := m.ctx.GetKey(keyIdentity, false)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
// In theory this value could be nil if (gpg --list-keys --with-colons) misses a "pub:" line
|
||||
// or a "fpr:" line, but gpg (in recent enough versions) prints that unconditionally. // codespell:ignore fpr
|
||||
return key.Fingerprint(), nil
|
||||
}
|
||||
|
||||
// UntrustedSignatureContents returns UNTRUSTED contents of the signature WITHOUT ANY VERIFICATION,
|
||||
// along with a short identifier of the key used for signing.
|
||||
// WARNING: The short key identifier (which corresponds to "Key ID" for OpenPGP keys)
|
||||
|
64
vendor/github.com/containers/image/v5/signature/mechanism_gpgme_only.go
generated
vendored
Normal file
64
vendor/github.com/containers/image/v5/signature/mechanism_gpgme_only.go
generated
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
//go:build !containers_image_openpgp && !containers_image_sequoia
|
||||
|
||||
package signature
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/proglottis/gpgme"
|
||||
)
|
||||
|
||||
// newEphemeralGPGSigningMechanism returns a new GPG/OpenPGP signing mechanism which
|
||||
// recognizes _only_ public keys from the supplied blobs, and returns the identities
|
||||
// of these keys.
|
||||
// The caller must call .Close() on the returned SigningMechanism.
|
||||
func newEphemeralGPGSigningMechanism(blobs [][]byte) (signingMechanismWithPassphrase, []string, error) {
|
||||
dir, err := os.MkdirTemp("", "containers-ephemeral-gpg-")
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
removeDir := true
|
||||
defer func() {
|
||||
if removeDir {
|
||||
os.RemoveAll(dir)
|
||||
}
|
||||
}()
|
||||
ctx, err := newGPGMEContext(dir)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
keyIdentities := []string{}
|
||||
for _, blob := range blobs {
|
||||
ki, err := importKeysFromBytes(ctx, blob)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
keyIdentities = append(keyIdentities, ki...)
|
||||
}
|
||||
|
||||
mech := newGPGMESigningMechanism(ctx, dir)
|
||||
removeDir = false
|
||||
return mech, keyIdentities, nil
|
||||
}
|
||||
|
||||
// importKeysFromBytes imports public keys from the supplied blob and returns their identities.
|
||||
// The blob is assumed to have an appropriate format (the caller is expected to know which one).
|
||||
// NOTE: This may modify long-term state (e.g. key storage in a directory underlying the mechanism);
|
||||
// but we do not make this public, it can only be used through newEphemeralGPGSigningMechanism.
|
||||
func importKeysFromBytes(ctx *gpgme.Context, blob []byte) ([]string, error) {
|
||||
inputData, err := gpgme.NewDataBytes(blob)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, err := ctx.Import(inputData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
keyIdentities := []string{}
|
||||
for _, i := range res.Imports {
|
||||
if i.Result == nil {
|
||||
keyIdentities = append(keyIdentities, i.Fingerprint)
|
||||
}
|
||||
}
|
||||
return keyIdentities, nil
|
||||
}
|
7
vendor/github.com/containers/image/v5/signature/mechanism_openpgp.go
generated
vendored
7
vendor/github.com/containers/image/v5/signature/mechanism_openpgp.go
generated
vendored
@@ -127,7 +127,10 @@ func (m *openpgpSigningMechanism) Sign(input []byte, keyIdentity string) ([]byte
|
||||
return m.SignWithPassphrase(input, keyIdentity, "")
|
||||
}
|
||||
|
||||
// Verify parses unverifiedSignature and returns the content and the signer's identity
|
||||
// Verify parses unverifiedSignature and returns the content and the signer's identity.
|
||||
// For mechanisms created using NewEphemeralGPGSigningMechanism, the returned key identity
|
||||
// is expected to be one of the values returned by NewEphemeralGPGSigningMechanism,
|
||||
// or the mechanism should implement signingMechanismWithVerificationIdentityLookup.
|
||||
func (m *openpgpSigningMechanism) Verify(unverifiedSignature []byte) (contents []byte, keyIdentity string, err error) {
|
||||
md, err := openpgp.ReadMessage(bytes.NewReader(unverifiedSignature), m.keyring, nil, nil)
|
||||
if err != nil {
|
||||
@@ -166,7 +169,7 @@ func (m *openpgpSigningMechanism) Verify(unverifiedSignature []byte) (contents [
|
||||
}
|
||||
|
||||
// Uppercase the fingerprint to be compatible with gpgme
|
||||
return content, strings.ToUpper(fmt.Sprintf("%x", md.SignedBy.PublicKey.Fingerprint)), nil
|
||||
return content, strings.ToUpper(fmt.Sprintf("%x", md.SignedBy.Entity.PrimaryKey.Fingerprint)), nil
|
||||
}
|
||||
|
||||
// UntrustedSignatureContents returns UNTRUSTED contents of the signature WITHOUT ANY VERIFICATION,
|
||||
|
84
vendor/github.com/containers/image/v5/signature/mechanism_sequoia.go
generated
vendored
Normal file
84
vendor/github.com/containers/image/v5/signature/mechanism_sequoia.go
generated
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
//go:build containers_image_sequoia
|
||||
|
||||
package signature
|
||||
|
||||
import (
|
||||
"github.com/containers/image/v5/signature/internal/sequoia"
|
||||
)
|
||||
|
||||
// A GPG/OpenPGP signing mechanism, implemented using Sequoia and only supporting verification.
|
||||
// Legacy users who reach newGPGSigningMechanismInDirectory will use GPGME.
|
||||
// Signing using Sequoia is preferable, but should happen via signature/simplesequoia.NewSigner, not using
|
||||
// the legacy mechanism API.
|
||||
type sequoiaEphemeralSigningMechanism struct {
|
||||
inner *sequoia.SigningMechanism
|
||||
}
|
||||
|
||||
// newEphemeralGPGSigningMechanism returns a new GPG/OpenPGP signing mechanism which
|
||||
// recognizes _only_ public keys from the supplied blobs, and returns the identities
|
||||
// of these keys.
|
||||
// The caller must call .Close() on the returned SigningMechanism.
|
||||
func newEphemeralGPGSigningMechanism(blobs [][]byte) (signingMechanismWithPassphrase, []string, error) {
|
||||
if err := sequoia.Init(); err != nil {
|
||||
return nil, nil, err // Coverage: This is impractical to test in-process, with the static go_sequoia_dlhandle.
|
||||
}
|
||||
|
||||
mech, err := sequoia.NewEphemeralMechanism()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
keyIdentities := []string{}
|
||||
for _, blob := range blobs {
|
||||
ki, err := mech.ImportKeys(blob)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
keyIdentities = append(keyIdentities, ki...)
|
||||
}
|
||||
|
||||
return &sequoiaEphemeralSigningMechanism{
|
||||
inner: mech,
|
||||
}, keyIdentities, nil
|
||||
}
|
||||
|
||||
func (m *sequoiaEphemeralSigningMechanism) Close() error {
|
||||
return m.inner.Close()
|
||||
}
|
||||
|
||||
// SupportsSigning returns nil if the mechanism supports signing, or a SigningNotSupportedError.
|
||||
func (m *sequoiaEphemeralSigningMechanism) SupportsSigning() error {
|
||||
// This code is externally reachable via NewEphemeralGPGSigningMechanism(), but that API provides no way to
|
||||
// import or generate a key.
|
||||
return SigningNotSupportedError("caller error: Attempt to sign using a mechanism created via NewEphemeralGPGSigningMechanism().")
|
||||
}
|
||||
|
||||
// Sign creates a (non-detached) signature of input using keyIdentity and passphrase.
|
||||
// Fails with a SigningNotSupportedError if the mechanism does not support signing.
|
||||
func (m *sequoiaEphemeralSigningMechanism) SignWithPassphrase(input []byte, keyIdentity string, passphrase string) ([]byte, error) {
|
||||
// This code is externally reachable via NewEphemeralGPGSigningMechanism(), but that API provides no way to
|
||||
// import or generate a key.
|
||||
return nil, SigningNotSupportedError("caller error: Attempt to sign using a mechanism created via NewEphemeralGPGSigningMechanism().")
|
||||
}
|
||||
|
||||
// Sign creates a (non-detached) signature of input using keyIdentity.
|
||||
// Fails with a SigningNotSupportedError if the mechanism does not support signing.
|
||||
func (m *sequoiaEphemeralSigningMechanism) Sign(input []byte, keyIdentity string) ([]byte, error) {
|
||||
return m.SignWithPassphrase(input, keyIdentity, "")
|
||||
}
|
||||
|
||||
// Verify parses unverifiedSignature and returns the content and the signer's identity.
|
||||
// For mechanisms created using NewEphemeralGPGSigningMechanism, the returned key identity
|
||||
// is expected to be one of the values returned by NewEphemeralGPGSigningMechanism,
|
||||
// or the mechanism should implement signingMechanismWithVerificationIdentityLookup.
|
||||
func (m *sequoiaEphemeralSigningMechanism) Verify(unverifiedSignature []byte) (contents []byte, keyIdentity string, err error) {
|
||||
return m.inner.Verify(unverifiedSignature)
|
||||
}
|
||||
|
||||
// UntrustedSignatureContents returns UNTRUSTED contents of the signature WITHOUT ANY VERIFICATION,
|
||||
// along with a short identifier of the key used for signing.
|
||||
// WARNING: The short key identifier (which corresponds to "Key ID" for OpenPGP keys)
|
||||
// is NOT the same as a "key identity" used in other calls to this interface, and
|
||||
// the values may have no recognizable relationship if the public key is not available.
|
||||
func (m *sequoiaEphemeralSigningMechanism) UntrustedSignatureContents(untrustedSignature []byte) (untrustedContents []byte, shortKeyIdentifier string, err error) {
|
||||
return gpgUntrustedSignatureContents(untrustedSignature)
|
||||
}
|
12
vendor/github.com/containers/image/v5/signature/policy_eval_signedby.go
generated
vendored
12
vendor/github.com/containers/image/v5/signature/policy_eval_signedby.go
generated
vendored
@@ -6,7 +6,6 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"slices"
|
||||
|
||||
"github.com/containers/image/v5/internal/multierr"
|
||||
"github.com/containers/image/v5/internal/private"
|
||||
@@ -50,15 +49,8 @@ func (pr *prSignedBy) isSignatureAuthorAccepted(ctx context.Context, image priva
|
||||
return sarRejected, nil, PolicyRequirementError("No public keys imported")
|
||||
}
|
||||
|
||||
signature, err := verifyAndExtractSignature(mech, sig, signatureAcceptanceRules{
|
||||
validateKeyIdentity: func(keyIdentity string) error {
|
||||
if slices.Contains(trustedIdentities, keyIdentity) {
|
||||
return nil
|
||||
}
|
||||
// Coverage: We use a private GPG home directory and only import trusted keys, so this should
|
||||
// not be reachable.
|
||||
return PolicyRequirementError(fmt.Sprintf("Signature by key %s is not accepted", keyIdentity))
|
||||
},
|
||||
signature, _, err := verifyAndExtractSignature(mech, sig, signatureAcceptanceRules{
|
||||
acceptedKeyIdentities: trustedIdentities,
|
||||
validateSignedDockerReference: func(ref string) error {
|
||||
if !pr.SignedIdentity.matchesDockerReference(image, ref) {
|
||||
return PolicyRequirementError(fmt.Sprintf("Signature for identity %q is not accepted", ref))
|
||||
|
36
vendor/github.com/containers/image/v5/signature/simple.go
generated
vendored
36
vendor/github.com/containers/image/v5/signature/simple.go
generated
vendored
@@ -8,6 +8,7 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"slices"
|
||||
"time"
|
||||
|
||||
"github.com/containers/image/v5/signature/internal"
|
||||
@@ -207,37 +208,52 @@ func (s untrustedSignature) sign(mech SigningMechanism, keyIdentity string, pass
|
||||
// because the functions have the same or similar types, so there is a risk of exchanging the functions;
|
||||
// named members of this struct are more explicit.
|
||||
type signatureAcceptanceRules struct {
|
||||
validateKeyIdentity func(string) error
|
||||
acceptedKeyIdentities []string
|
||||
validateSignedDockerReference func(string) error
|
||||
validateSignedDockerManifestDigest func(digest.Digest) error
|
||||
}
|
||||
|
||||
// verifyAndExtractSignature verifies that unverifiedSignature has been signed, and that its principal components
|
||||
// match expected values, both as specified by rules, and returns it
|
||||
func verifyAndExtractSignature(mech SigningMechanism, unverifiedSignature []byte, rules signatureAcceptanceRules) (*Signature, error) {
|
||||
// match expected values, both as specified by rules.
|
||||
// Returns the signature, and an identity of the key that signed it.
|
||||
func verifyAndExtractSignature(mech SigningMechanism, unverifiedSignature []byte, rules signatureAcceptanceRules) (*Signature, string, error) {
|
||||
signed, keyIdentity, err := mech.Verify(unverifiedSignature)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, "", err
|
||||
}
|
||||
if err := rules.validateKeyIdentity(keyIdentity); err != nil {
|
||||
return nil, err
|
||||
if !slices.Contains(rules.acceptedKeyIdentities, keyIdentity) {
|
||||
withLookup, ok := mech.(signingMechanismWithVerificationIdentityLookup)
|
||||
if !ok {
|
||||
return nil, "", internal.NewInvalidSignatureError(fmt.Sprintf("signature by key %s is not accepted", keyIdentity))
|
||||
}
|
||||
|
||||
primaryKey, err := withLookup.keyIdentityForVerificationKeyIdentity(keyIdentity)
|
||||
if err != nil {
|
||||
// Coverage: This only fails if lookup by keyIdentity fails, but we just found and used that key.
|
||||
// Or maybe on some unexpected I/O error.
|
||||
return nil, "", err
|
||||
}
|
||||
if !slices.Contains(rules.acceptedKeyIdentities, primaryKey) {
|
||||
return nil, "", internal.NewInvalidSignatureError(fmt.Sprintf("signature by key %s of %s is not accepted", keyIdentity, primaryKey))
|
||||
}
|
||||
keyIdentity = primaryKey
|
||||
}
|
||||
|
||||
var unmatchedSignature untrustedSignature
|
||||
if err := json.Unmarshal(signed, &unmatchedSignature); err != nil {
|
||||
return nil, internal.NewInvalidSignatureError(err.Error())
|
||||
return nil, "", internal.NewInvalidSignatureError(err.Error())
|
||||
}
|
||||
if err := rules.validateSignedDockerManifestDigest(unmatchedSignature.untrustedDockerManifestDigest); err != nil {
|
||||
return nil, err
|
||||
return nil, "", err
|
||||
}
|
||||
if err := rules.validateSignedDockerReference(unmatchedSignature.untrustedDockerReference); err != nil {
|
||||
return nil, err
|
||||
return nil, "", err
|
||||
}
|
||||
// signatureAcceptanceRules have accepted this value.
|
||||
return &Signature{
|
||||
DockerManifestDigest: unmatchedSignature.untrustedDockerManifestDigest,
|
||||
DockerReference: unmatchedSignature.untrustedDockerReference,
|
||||
}, nil
|
||||
}, keyIdentity, nil
|
||||
}
|
||||
|
||||
// GetUntrustedSignatureInformationWithoutVerifying extracts information available in an untrusted signature,
|
||||
|
4
vendor/modules.txt
vendored
4
vendor/modules.txt
vendored
@@ -79,7 +79,7 @@ github.com/containers/common/pkg/password
|
||||
github.com/containers/common/pkg/report
|
||||
github.com/containers/common/pkg/report/camelcase
|
||||
github.com/containers/common/pkg/retry
|
||||
# github.com/containers/image/v5 v5.36.2-0.20250807195248-f8cef395fcde
|
||||
# github.com/containers/image/v5 v5.36.2-0.20250807195248-f8cef395fcde => github.com/mtrmac/image/v5 v5.0.0-20250807201425-55d1eaf519bd
|
||||
## explicit; go 1.23.3
|
||||
github.com/containers/image/v5/copy
|
||||
github.com/containers/image/v5/directory
|
||||
@@ -137,6 +137,7 @@ github.com/containers/image/v5/pkg/tlsclientconfig
|
||||
github.com/containers/image/v5/sif
|
||||
github.com/containers/image/v5/signature
|
||||
github.com/containers/image/v5/signature/internal
|
||||
github.com/containers/image/v5/signature/internal/sequoia
|
||||
github.com/containers/image/v5/signature/signer
|
||||
github.com/containers/image/v5/signature/sigstore
|
||||
github.com/containers/image/v5/signature/sigstore/fulcio
|
||||
@@ -711,3 +712,4 @@ google.golang.org/protobuf/types/known/timestamppb
|
||||
# gopkg.in/yaml.v3 v3.0.1
|
||||
## explicit
|
||||
gopkg.in/yaml.v3
|
||||
# github.com/containers/image/v5 => github.com/mtrmac/image/v5 v5.0.0-20250807201425-55d1eaf519bd
|
||||
|
Reference in New Issue
Block a user