1
0
mirror of https://github.com/containers/skopeo.git synced 2025-05-02 13:13:24 +00:00

Merge pull request from mtrmac/gpgme-update-0.1.32

Update to github.com/mtrmac/gpgme v0.1.2
This commit is contained in:
Daniel J Walsh 2020-02-21 10:18:17 -05:00 committed by GitHub
commit e5c9d5790c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 361 additions and 82 deletions

View File

@ -1,6 +1,6 @@
FROM fedora FROM fedora
RUN dnf -y update && dnf install -y make git golang golang-github-cpuguy83-go-md2man \ RUN dnf -y update && dnf install -y make git golang golang-github-cpuguy83-md2man \
# storage deps # storage deps
btrfs-progs-devel \ btrfs-progs-devel \
device-mapper-devel \ device-mapper-devel \

View File

@ -14,7 +14,7 @@ import (
"github.com/containers/image/manifest" "github.com/containers/image/manifest"
"github.com/containers/image/signature" "github.com/containers/image/signature"
"github.com/go-check/check" "github.com/go-check/check"
"github.com/opencontainers/go-digest" digest "github.com/opencontainers/go-digest"
imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1" imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/opencontainers/image-tools/image" "github.com/opencontainers/image-tools/image"
) )
@ -64,7 +64,7 @@ func (s *CopySuite) SetUpSuite(c *check.C) {
os.Setenv("GNUPGHOME", s.gpgHome) os.Setenv("GNUPGHOME", s.gpgHome)
for _, key := range []string{"personal", "official"} { for _, key := range []string{"personal", "official"} {
batchInput := fmt.Sprintf("Key-Type: RSA\nName-Real: Test key - %s\nName-email: %s@example.com\n%%commit\n", batchInput := fmt.Sprintf("Key-Type: RSA\nName-Real: Test key - %s\nName-email: %s@example.com\n%%no-protection\n%%commit\n",
key, key) key, key)
runCommandWithInput(c, batchInput, gpgBinary, "--batch", "--gen-key") runCommandWithInput(c, batchInput, gpgBinary, "--batch", "--gen-key")

View File

@ -44,7 +44,7 @@ func (s *SigningSuite) SetUpSuite(c *check.C) {
c.Assert(err, check.IsNil) c.Assert(err, check.IsNil)
os.Setenv("GNUPGHOME", s.gpgHome) os.Setenv("GNUPGHOME", s.gpgHome)
runCommandWithInput(c, "Key-Type: RSA\nName-Real: Testing user\n%commit\n", gpgBinary, "--homedir", s.gpgHome, "--batch", "--gen-key") runCommandWithInput(c, "Key-Type: RSA\nName-Real: Testing user\n%no-protection\n%commit\n", gpgBinary, "--homedir", s.gpgHome, "--batch", "--gen-key")
lines, err := exec.Command(gpgBinary, "--homedir", s.gpgHome, "--with-colons", "--no-permission-warning", "--fingerprint").Output() lines, err := exec.Command(gpgBinary, "--homedir", s.gpgHome, "--with-colons", "--no-permission-warning", "--fingerprint").Output()
c.Assert(err, check.IsNil) c.Assert(err, check.IsNil)

View File

@ -49,7 +49,7 @@ github.com/xeipuuv/gojsonpointer master
go4.org master https://github.com/camlistore/go4 go4.org master https://github.com/camlistore/go4
github.com/ostreedev/ostree-go aeb02c6b6aa2889db3ef62f7855650755befd460 github.com/ostreedev/ostree-go aeb02c6b6aa2889db3ef62f7855650755befd460
# -- end OCI image validation requirements # -- end OCI image validation requirements
github.com/mtrmac/gpgme master github.com/mtrmac/gpgme v0.1.2
# openshift/origin' k8s dependencies as of OpenShift v1.1.5 # openshift/origin' k8s dependencies as of OpenShift v1.1.5
k8s.io/client-go master k8s.io/client-go master
github.com/ghodss/yaml 73d445a93680fa1a78ae23a5839bad48f32ba1ee github.com/ghodss/yaml 73d445a93680fa1a78ae23a5839bad48f32ba1ee

View File

@ -50,25 +50,25 @@ func gogpgme_writefunc(handle, buffer unsafe.Pointer, size C.size_t) C.ssize_t {
} }
//export gogpgme_seekfunc //export gogpgme_seekfunc
func gogpgme_seekfunc(handle unsafe.Pointer, offset C.off_t, whence C.int) C.off_t { func gogpgme_seekfunc(handle unsafe.Pointer, offset C.gpgme_off_t, whence C.int) C.gpgme_off_t {
d := callbackLookup(uintptr(handle)).(*Data) d := callbackLookup(uintptr(handle)).(*Data)
n, err := d.s.Seek(int64(offset), int(whence)) n, err := d.s.Seek(int64(offset), int(whence))
if err != nil { if err != nil {
C.gpgme_err_set_errno(C.EIO) C.gpgme_err_set_errno(C.EIO)
return -1 return -1
} }
return C.off_t(n) return C.gpgme_off_t(n)
} }
// The Data buffer used to communicate with GPGME // The Data buffer used to communicate with GPGME
type Data struct { type Data struct {
dh C.gpgme_data_t dh C.gpgme_data_t // WARNING: Call runtime.KeepAlive(d) after ANY passing of d.dh to C
buf []byte buf []byte
cbs C.struct_gpgme_data_cbs cbs C.struct_gpgme_data_cbs
r io.Reader r io.Reader
w io.Writer w io.Writer
s io.Seeker s io.Seeker
cbc uintptr cbc uintptr // WARNING: Call runtime.KeepAlive(d) after ANY use of d.cbc in C (typically via d.dh)
} }
func newData() *Data { func newData() *Data {
@ -154,12 +154,14 @@ func (d *Data) Close() error {
callbackDelete(d.cbc) callbackDelete(d.cbc)
} }
_, err := C.gpgme_data_release(d.dh) _, err := C.gpgme_data_release(d.dh)
runtime.KeepAlive(d)
d.dh = nil d.dh = nil
return err return err
} }
func (d *Data) Write(p []byte) (int, error) { func (d *Data) Write(p []byte) (int, error) {
n, err := C.gpgme_data_write(d.dh, unsafe.Pointer(&p[0]), C.size_t(len(p))) n, err := C.gpgme_data_write(d.dh, unsafe.Pointer(&p[0]), C.size_t(len(p)))
runtime.KeepAlive(d)
if err != nil { if err != nil {
return 0, err return 0, err
} }
@ -171,6 +173,7 @@ func (d *Data) Write(p []byte) (int, error) {
func (d *Data) Read(p []byte) (int, error) { func (d *Data) Read(p []byte) (int, error) {
n, err := C.gpgme_data_read(d.dh, unsafe.Pointer(&p[0]), C.size_t(len(p))) n, err := C.gpgme_data_read(d.dh, unsafe.Pointer(&p[0]), C.size_t(len(p)))
runtime.KeepAlive(d)
if err != nil { if err != nil {
return 0, err return 0, err
} }
@ -181,11 +184,14 @@ func (d *Data) Read(p []byte) (int, error) {
} }
func (d *Data) Seek(offset int64, whence int) (int64, error) { func (d *Data) Seek(offset int64, whence int) (int64, error) {
n, err := C.gpgme_data_seek(d.dh, C.off_t(offset), C.int(whence)) n, err := C.gogpgme_data_seek(d.dh, C.gpgme_off_t(offset), C.int(whence))
runtime.KeepAlive(d)
return int64(n), err return int64(n), err
} }
// Name returns the associated filename if any // Name returns the associated filename if any
func (d *Data) Name() string { func (d *Data) Name() string {
return C.GoString(C.gpgme_data_get_file_name(d.dh)) res := C.GoString(C.gpgme_data_get_file_name(d.dh))
runtime.KeepAlive(d)
return res
} }

3
vendor/github.com/mtrmac/gpgme/go.mod generated vendored Normal file
View File

@ -0,0 +1,3 @@
module github.com/mtrmac/gpgme
go 1.11

View File

@ -8,6 +8,28 @@ void gogpgme_set_passphrase_cb(gpgme_ctx_t ctx, gpgme_passphrase_cb_t cb, uintpt
gpgme_set_passphrase_cb(ctx, cb, (void *)handle); gpgme_set_passphrase_cb(ctx, cb, (void *)handle);
} }
gpgme_off_t gogpgme_data_seek(gpgme_data_t dh, gpgme_off_t offset, int whence) {
return gpgme_data_seek(dh, offset, whence);
}
gpgme_error_t gogpgme_op_assuan_transact_ext(
gpgme_ctx_t ctx,
char* cmd,
uintptr_t data_h,
uintptr_t inquiry_h,
uintptr_t status_h,
gpgme_error_t *operr
){
return gpgme_op_assuan_transact_ext(
ctx,
cmd,
(gpgme_assuan_data_cb_t) gogpgme_assuan_data_callback, (void *)data_h,
(gpgme_assuan_inquire_cb_t) gogpgme_assuan_inquiry_callback, (void *)inquiry_h,
(gpgme_assuan_status_cb_t) gogpgme_assuan_status_callback, (void *)status_h,
operr
);
}
unsigned int key_revoked(gpgme_key_t k) { unsigned int key_revoked(gpgme_key_t k) {
return k->revoked; return k->revoked;
} }

View File

@ -6,12 +6,24 @@
#include <gpgme.h> #include <gpgme.h>
/* GPGME_VERSION_NUMBER was introduced in 1.4.0 */
#if !defined(GPGME_VERSION_NUMBER) || GPGME_VERSION_NUMBER < 0x010402
typedef off_t gpgme_off_t; /* Introduced in 1.4.2 */
#endif
extern ssize_t gogpgme_readfunc(void *handle, void *buffer, size_t size); extern ssize_t gogpgme_readfunc(void *handle, void *buffer, size_t size);
extern ssize_t gogpgme_writefunc(void *handle, void *buffer, size_t size); extern ssize_t gogpgme_writefunc(void *handle, void *buffer, size_t size);
extern off_t gogpgme_seekfunc(void *handle, off_t offset, int whence); extern off_t gogpgme_seekfunc(void *handle, off_t offset, int whence);
extern gpgme_error_t gogpgme_passfunc(void *hook, char *uid_hint, char *passphrase_info, int prev_was_bad, int fd); extern gpgme_error_t gogpgme_passfunc(void *hook, char *uid_hint, char *passphrase_info, int prev_was_bad, int fd);
extern gpgme_error_t gogpgme_data_new_from_cbs(gpgme_data_t *dh, gpgme_data_cbs_t cbs, uintptr_t handle); extern gpgme_error_t gogpgme_data_new_from_cbs(gpgme_data_t *dh, gpgme_data_cbs_t cbs, uintptr_t handle);
extern void gogpgme_set_passphrase_cb(gpgme_ctx_t ctx, gpgme_passphrase_cb_t cb, uintptr_t handle); extern void gogpgme_set_passphrase_cb(gpgme_ctx_t ctx, gpgme_passphrase_cb_t cb, uintptr_t handle);
extern gpgme_off_t gogpgme_data_seek(gpgme_data_t dh, gpgme_off_t offset, int whence);
extern gpgme_error_t gogpgme_op_assuan_transact_ext(gpgme_ctx_t ctx, char *cmd, uintptr_t data_h, uintptr_t inquiry_h , uintptr_t status_h, gpgme_error_t *operr);
extern gpgme_error_t gogpgme_assuan_data_callback(void *opaque, void* data, size_t datalen );
extern gpgme_error_t gogpgme_assuan_inquiry_callback(void *opaque, char* name, char* args);
extern gpgme_error_t gogpgme_assuan_status_callback(void *opaque, char* status, char* args);
extern unsigned int key_revoked(gpgme_key_t k); extern unsigned int key_revoked(gpgme_key_t k);
extern unsigned int key_expired(gpgme_key_t k); extern unsigned int key_expired(gpgme_key_t k);

View File

@ -7,7 +7,6 @@ package gpgme
// #include <gpgme.h> // #include <gpgme.h>
// #include "go_gpgme.h" // #include "go_gpgme.h"
import "C" import "C"
import ( import (
"fmt" "fmt"
"io" "io"
@ -48,7 +47,6 @@ const (
ProtocolAssuan Protocol = C.GPGME_PROTOCOL_ASSUAN ProtocolAssuan Protocol = C.GPGME_PROTOCOL_ASSUAN
ProtocolG13 Protocol = C.GPGME_PROTOCOL_G13 ProtocolG13 Protocol = C.GPGME_PROTOCOL_G13
ProtocolUIServer Protocol = C.GPGME_PROTOCOL_UISERVER ProtocolUIServer Protocol = C.GPGME_PROTOCOL_UISERVER
// ProtocolSpawn Protocol = C.GPGME_PROTOCOL_SPAWN // Unavailable in 1.4.3
ProtocolDefault Protocol = C.GPGME_PROTOCOL_DEFAULT ProtocolDefault Protocol = C.GPGME_PROTOCOL_DEFAULT
ProtocolUnknown Protocol = C.GPGME_PROTOCOL_UNKNOWN ProtocolUnknown Protocol = C.GPGME_PROTOCOL_UNKNOWN
) )
@ -70,7 +68,6 @@ const (
EncryptNoEncryptTo EncryptFlag = C.GPGME_ENCRYPT_NO_ENCRYPT_TO EncryptNoEncryptTo EncryptFlag = C.GPGME_ENCRYPT_NO_ENCRYPT_TO
EncryptPrepare EncryptFlag = C.GPGME_ENCRYPT_PREPARE EncryptPrepare EncryptFlag = C.GPGME_ENCRYPT_PREPARE
EncryptExceptSign EncryptFlag = C.GPGME_ENCRYPT_EXPECT_SIGN EncryptExceptSign EncryptFlag = C.GPGME_ENCRYPT_EXPECT_SIGN
// EncryptNoCompress EncryptFlag = C.GPGME_ENCRYPT_NO_COMPRESS // Unavailable in 1.4.3
) )
type HashAlgo int type HashAlgo int
@ -84,7 +81,6 @@ const (
KeyListModeExtern KeyListMode = C.GPGME_KEYLIST_MODE_EXTERN KeyListModeExtern KeyListMode = C.GPGME_KEYLIST_MODE_EXTERN
KeyListModeSigs KeyListMode = C.GPGME_KEYLIST_MODE_SIGS KeyListModeSigs KeyListMode = C.GPGME_KEYLIST_MODE_SIGS
KeyListModeSigNotations KeyListMode = C.GPGME_KEYLIST_MODE_SIG_NOTATIONS KeyListModeSigNotations KeyListMode = C.GPGME_KEYLIST_MODE_SIG_NOTATIONS
// KeyListModeWithSecret KeyListMode = C.GPGME_KEYLIST_MODE_WITH_SECRET // Unavailable in 1.4.3
KeyListModeEphemeral KeyListMode = C.GPGME_KEYLIST_MODE_EPHEMERAL KeyListModeEphemeral KeyListMode = C.GPGME_KEYLIST_MODE_EPHEMERAL
KeyListModeModeValidate KeyListMode = C.GPGME_KEYLIST_MODE_VALIDATE KeyListModeModeValidate KeyListMode = C.GPGME_KEYLIST_MODE_VALIDATE
) )
@ -168,39 +164,60 @@ func EngineCheckVersion(p Protocol) error {
} }
type EngineInfo struct { type EngineInfo struct {
info C.gpgme_engine_info_t next *EngineInfo
protocol Protocol
fileName string
homeDir string
version string
requiredVersion string
}
func copyEngineInfo(info C.gpgme_engine_info_t) *EngineInfo {
res := &EngineInfo{
next: nil,
protocol: Protocol(info.protocol),
fileName: C.GoString(info.file_name),
homeDir: C.GoString(info.home_dir),
version: C.GoString(info.version),
requiredVersion: C.GoString(info.req_version),
}
if info.next != nil {
res.next = copyEngineInfo(info.next)
}
return res
} }
func (e *EngineInfo) Next() *EngineInfo { func (e *EngineInfo) Next() *EngineInfo {
if e.info.next == nil { return e.next
return nil
}
return &EngineInfo{info: e.info.next}
} }
func (e *EngineInfo) Protocol() Protocol { func (e *EngineInfo) Protocol() Protocol {
return Protocol(e.info.protocol) return e.protocol
} }
func (e *EngineInfo) FileName() string { func (e *EngineInfo) FileName() string {
return C.GoString(e.info.file_name) return e.fileName
} }
func (e *EngineInfo) Version() string { func (e *EngineInfo) Version() string {
return C.GoString(e.info.version) return e.version
} }
func (e *EngineInfo) RequiredVersion() string { func (e *EngineInfo) RequiredVersion() string {
return C.GoString(e.info.req_version) return e.requiredVersion
} }
func (e *EngineInfo) HomeDir() string { func (e *EngineInfo) HomeDir() string {
return C.GoString(e.info.home_dir) return e.homeDir
} }
func GetEngineInfo() (*EngineInfo, error) { func GetEngineInfo() (*EngineInfo, error) {
info := &EngineInfo{} var cInfo C.gpgme_engine_info_t
return info, handleError(C.gpgme_get_engine_info(&info.info)) err := handleError(C.gpgme_get_engine_info(&cInfo))
if err != nil {
return nil, err
}
return copyEngineInfo(cInfo), nil // It is up to the caller not to invalidate cInfo concurrently until this is done.
} }
func SetEngineInfo(proto Protocol, fileName, homeDir string) error { func SetEngineInfo(proto Protocol, fileName, homeDir string) error {
@ -261,9 +278,9 @@ type Context struct {
KeyError error KeyError error
callback Callback callback Callback
cbc uintptr cbc uintptr // WARNING: Call runtime.KeepAlive(c) after ANY use of c.cbc in C (typically via c.ctx)
ctx C.gpgme_ctx_t ctx C.gpgme_ctx_t // WARNING: Call runtime.KeepAlive(c) after ANY passing of c.ctx to C
} }
func New() (*Context, error) { func New() (*Context, error) {
@ -281,49 +298,68 @@ func (c *Context) Release() {
callbackDelete(c.cbc) callbackDelete(c.cbc)
} }
C.gpgme_release(c.ctx) C.gpgme_release(c.ctx)
runtime.KeepAlive(c)
c.ctx = nil c.ctx = nil
} }
func (c *Context) SetArmor(yes bool) { func (c *Context) SetArmor(yes bool) {
C.gpgme_set_armor(c.ctx, cbool(yes)) C.gpgme_set_armor(c.ctx, cbool(yes))
runtime.KeepAlive(c)
} }
func (c *Context) Armor() bool { func (c *Context) Armor() bool {
return C.gpgme_get_armor(c.ctx) != 0 res := C.gpgme_get_armor(c.ctx) != 0
runtime.KeepAlive(c)
return res
} }
func (c *Context) SetTextMode(yes bool) { func (c *Context) SetTextMode(yes bool) {
C.gpgme_set_textmode(c.ctx, cbool(yes)) C.gpgme_set_textmode(c.ctx, cbool(yes))
runtime.KeepAlive(c)
} }
func (c *Context) TextMode() bool { func (c *Context) TextMode() bool {
return C.gpgme_get_textmode(c.ctx) != 0 res := C.gpgme_get_textmode(c.ctx) != 0
runtime.KeepAlive(c)
return res
} }
func (c *Context) SetProtocol(p Protocol) error { func (c *Context) SetProtocol(p Protocol) error {
return handleError(C.gpgme_set_protocol(c.ctx, C.gpgme_protocol_t(p))) err := handleError(C.gpgme_set_protocol(c.ctx, C.gpgme_protocol_t(p)))
runtime.KeepAlive(c)
return err
} }
func (c *Context) Protocol() Protocol { func (c *Context) Protocol() Protocol {
return Protocol(C.gpgme_get_protocol(c.ctx)) res := Protocol(C.gpgme_get_protocol(c.ctx))
runtime.KeepAlive(c)
return res
} }
func (c *Context) SetKeyListMode(m KeyListMode) error { func (c *Context) SetKeyListMode(m KeyListMode) error {
return handleError(C.gpgme_set_keylist_mode(c.ctx, C.gpgme_keylist_mode_t(m))) err := handleError(C.gpgme_set_keylist_mode(c.ctx, C.gpgme_keylist_mode_t(m)))
runtime.KeepAlive(c)
return err
} }
func (c *Context) KeyListMode() KeyListMode { func (c *Context) KeyListMode() KeyListMode {
return KeyListMode(C.gpgme_get_keylist_mode(c.ctx)) res := KeyListMode(C.gpgme_get_keylist_mode(c.ctx))
runtime.KeepAlive(c)
return res
} }
// Unavailable in 1.3.2: // Unavailable in 1.3.2:
// func (c *Context) SetPinEntryMode(m PinEntryMode) error { // func (c *Context) SetPinEntryMode(m PinEntryMode) error {
// return handleError(C.gpgme_set_pinentry_mode(c.ctx, C.gpgme_pinentry_mode_t(m))) // err := handleError(C.gpgme_set_pinentry_mode(c.ctx, C.gpgme_pinentry_mode_t(m)))
// runtime.KeepAlive(c)
// return err
// } // }
// Unavailable in 1.3.2: // Unavailable in 1.3.2:
// func (c *Context) PinEntryMode() PinEntryMode { // func (c *Context) PinEntryMode() PinEntryMode {
// return PinEntryMode(C.gpgme_get_pinentry_mode(c.ctx)) // res := PinEntryMode(C.gpgme_get_pinentry_mode(c.ctx))
// runtime.KeepAlive(c)
// return res
// } // }
func (c *Context) SetCallback(callback Callback) error { func (c *Context) SetCallback(callback Callback) error {
@ -340,11 +376,17 @@ func (c *Context) SetCallback(callback Callback) error {
c.cbc = 0 c.cbc = 0
_, err = C.gogpgme_set_passphrase_cb(c.ctx, nil, 0) _, err = C.gogpgme_set_passphrase_cb(c.ctx, nil, 0)
} }
runtime.KeepAlive(c)
return err return err
} }
func (c *Context) EngineInfo() *EngineInfo { func (c *Context) EngineInfo() *EngineInfo {
return &EngineInfo{info: C.gpgme_ctx_get_engine_info(c.ctx)} cInfo := C.gpgme_ctx_get_engine_info(c.ctx)
runtime.KeepAlive(c)
// NOTE: c must be live as long as we are accessing cInfo.
res := copyEngineInfo(cInfo)
runtime.KeepAlive(c) // for accesses to cInfo
return res
} }
func (c *Context) SetEngineInfo(proto Protocol, fileName, homeDir string) error { func (c *Context) SetEngineInfo(proto Protocol, fileName, homeDir string) error {
@ -357,19 +399,23 @@ func (c *Context) SetEngineInfo(proto Protocol, fileName, homeDir string) error
chome = C.CString(homeDir) chome = C.CString(homeDir)
defer C.free(unsafe.Pointer(chome)) defer C.free(unsafe.Pointer(chome))
} }
return handleError(C.gpgme_ctx_set_engine_info(c.ctx, C.gpgme_protocol_t(proto), cfn, chome)) err := handleError(C.gpgme_ctx_set_engine_info(c.ctx, C.gpgme_protocol_t(proto), cfn, chome))
runtime.KeepAlive(c)
return err
} }
func (c *Context) KeyListStart(pattern string, secretOnly bool) error { func (c *Context) KeyListStart(pattern string, secretOnly bool) error {
cpattern := C.CString(pattern) cpattern := C.CString(pattern)
defer C.free(unsafe.Pointer(cpattern)) defer C.free(unsafe.Pointer(cpattern))
err := C.gpgme_op_keylist_start(c.ctx, cpattern, cbool(secretOnly)) err := handleError(C.gpgme_op_keylist_start(c.ctx, cpattern, cbool(secretOnly)))
return handleError(err) runtime.KeepAlive(c)
return err
} }
func (c *Context) KeyListNext() bool { func (c *Context) KeyListNext() bool {
c.Key = newKey() c.Key = newKey()
err := handleError(C.gpgme_op_keylist_next(c.ctx, &c.Key.k)) err := handleError(C.gpgme_op_keylist_next(c.ctx, &c.Key.k))
runtime.KeepAlive(c) // implies runtime.KeepAlive(c.Key)
if err != nil { if err != nil {
if e, ok := err.(Error); ok && e.Code() == ErrorEOF { if e, ok := err.(Error); ok && e.Code() == ErrorEOF {
c.KeyError = nil c.KeyError = nil
@ -383,7 +429,9 @@ func (c *Context) KeyListNext() bool {
} }
func (c *Context) KeyListEnd() error { func (c *Context) KeyListEnd() error {
return handleError(C.gpgme_op_keylist_end(c.ctx)) err := handleError(C.gpgme_op_keylist_end(c.ctx))
runtime.KeepAlive(c)
return err
} }
func (c *Context) GetKey(fingerprint string, secret bool) (*Key, error) { func (c *Context) GetKey(fingerprint string, secret bool) (*Key, error) {
@ -391,7 +439,11 @@ func (c *Context) GetKey(fingerprint string, secret bool) (*Key, error) {
cfpr := C.CString(fingerprint) cfpr := C.CString(fingerprint)
defer C.free(unsafe.Pointer(cfpr)) defer C.free(unsafe.Pointer(cfpr))
err := handleError(C.gpgme_get_key(c.ctx, cfpr, &key.k, cbool(secret))) err := handleError(C.gpgme_get_key(c.ctx, cfpr, &key.k, cbool(secret)))
if e, ok := err.(Error); key.k == nil && ok && e.Code() == ErrorEOF { runtime.KeepAlive(c)
runtime.KeepAlive(key)
keyKIsNil := key.k == nil
runtime.KeepAlive(key)
if e, ok := err.(Error); keyKIsNil && ok && e.Code() == ErrorEOF {
return nil, fmt.Errorf("key %q not found", fingerprint) return nil, fmt.Errorf("key %q not found", fingerprint)
} }
if err != nil { if err != nil {
@ -401,11 +453,19 @@ func (c *Context) GetKey(fingerprint string, secret bool) (*Key, error) {
} }
func (c *Context) Decrypt(ciphertext, plaintext *Data) error { func (c *Context) Decrypt(ciphertext, plaintext *Data) error {
return handleError(C.gpgme_op_decrypt(c.ctx, ciphertext.dh, plaintext.dh)) err := handleError(C.gpgme_op_decrypt(c.ctx, ciphertext.dh, plaintext.dh))
runtime.KeepAlive(c)
runtime.KeepAlive(ciphertext)
runtime.KeepAlive(plaintext)
return err
} }
func (c *Context) DecryptVerify(ciphertext, plaintext *Data) error { func (c *Context) DecryptVerify(ciphertext, plaintext *Data) error {
return handleError(C.gpgme_op_decrypt_verify(c.ctx, ciphertext.dh, plaintext.dh)) err := handleError(C.gpgme_op_decrypt_verify(c.ctx, ciphertext.dh, plaintext.dh))
runtime.KeepAlive(c)
runtime.KeepAlive(ciphertext)
runtime.KeepAlive(plaintext)
return err
} }
type Signature struct { type Signature struct {
@ -432,10 +492,20 @@ func (c *Context) Verify(sig, signedText, plain *Data) (string, []Signature, err
plainPtr = plain.dh plainPtr = plain.dh
} }
err := handleError(C.gpgme_op_verify(c.ctx, sig.dh, signedTextPtr, plainPtr)) err := handleError(C.gpgme_op_verify(c.ctx, sig.dh, signedTextPtr, plainPtr))
runtime.KeepAlive(c)
runtime.KeepAlive(sig)
if signedText != nil {
runtime.KeepAlive(signedText)
}
if plain != nil {
runtime.KeepAlive(plain)
}
if err != nil { if err != nil {
return "", nil, err return "", nil, err
} }
res := C.gpgme_op_verify_result(c.ctx) res := C.gpgme_op_verify_result(c.ctx)
runtime.KeepAlive(c)
// NOTE: c must be live as long as we are accessing res.
sigs := []Signature{} sigs := []Signature{}
for s := res.signatures; s != nil; s = s.next { for s := res.signatures; s != nil; s = s.next {
sig := Signature{ sig := Signature{
@ -455,7 +525,9 @@ func (c *Context) Verify(sig, signedText, plain *Data) (string, []Signature, err
} }
sigs = append(sigs, sig) sigs = append(sigs, sig)
} }
return C.GoString(res.file_name), sigs, nil fileName := C.GoString(res.file_name)
runtime.KeepAlive(c) // for all accesses to res above
return fileName, sigs, nil
} }
func (c *Context) Encrypt(recipients []*Key, flags EncryptFlag, plaintext, ciphertext *Data) error { func (c *Context) Encrypt(recipients []*Key, flags EncryptFlag, plaintext, ciphertext *Data) error {
@ -467,18 +539,116 @@ func (c *Context) Encrypt(recipients []*Key, flags EncryptFlag, plaintext, ciphe
*ptr = recipients[i].k *ptr = recipients[i].k
} }
err := C.gpgme_op_encrypt(c.ctx, (*C.gpgme_key_t)(recp), C.gpgme_encrypt_flags_t(flags), plaintext.dh, ciphertext.dh) err := C.gpgme_op_encrypt(c.ctx, (*C.gpgme_key_t)(recp), C.gpgme_encrypt_flags_t(flags), plaintext.dh, ciphertext.dh)
runtime.KeepAlive(c)
runtime.KeepAlive(recipients)
runtime.KeepAlive(plaintext)
runtime.KeepAlive(ciphertext)
return handleError(err) return handleError(err)
} }
func (c *Context) Sign(signers []*Key, plain, sig *Data, mode SigMode) error { func (c *Context) Sign(signers []*Key, plain, sig *Data, mode SigMode) error {
C.gpgme_signers_clear(c.ctx) C.gpgme_signers_clear(c.ctx)
runtime.KeepAlive(c)
for _, k := range signers { for _, k := range signers {
if err := handleError(C.gpgme_signers_add(c.ctx, k.k)); err != nil { err := handleError(C.gpgme_signers_add(c.ctx, k.k))
runtime.KeepAlive(c)
runtime.KeepAlive(k)
if err != nil {
C.gpgme_signers_clear(c.ctx) C.gpgme_signers_clear(c.ctx)
runtime.KeepAlive(c)
return err return err
} }
} }
return handleError(C.gpgme_op_sign(c.ctx, plain.dh, sig.dh, C.gpgme_sig_mode_t(mode))) err := handleError(C.gpgme_op_sign(c.ctx, plain.dh, sig.dh, C.gpgme_sig_mode_t(mode)))
runtime.KeepAlive(c)
runtime.KeepAlive(plain)
runtime.KeepAlive(sig)
return err
}
type AssuanDataCallback func(data []byte) error
type AssuanInquireCallback func(name, args string) error
type AssuanStatusCallback func(status, args string) error
// AssuanSend sends a raw Assuan command to gpg-agent
func (c *Context) AssuanSend(
cmd string,
data AssuanDataCallback,
inquiry AssuanInquireCallback,
status AssuanStatusCallback,
) error {
var operr C.gpgme_error_t
dataPtr := callbackAdd(&data)
inquiryPtr := callbackAdd(&inquiry)
statusPtr := callbackAdd(&status)
cmdCStr := C.CString(cmd)
defer C.free(unsafe.Pointer(cmdCStr))
err := C.gogpgme_op_assuan_transact_ext(
c.ctx,
cmdCStr,
C.uintptr_t(dataPtr),
C.uintptr_t(inquiryPtr),
C.uintptr_t(statusPtr),
&operr,
)
runtime.KeepAlive(c)
if handleError(operr) != nil {
return handleError(operr)
}
return handleError(err)
}
//export gogpgme_assuan_data_callback
func gogpgme_assuan_data_callback(handle unsafe.Pointer, data unsafe.Pointer, datalen C.size_t) C.gpgme_error_t {
c := callbackLookup(uintptr(handle)).(*AssuanDataCallback)
if *c == nil {
return 0
}
(*c)(C.GoBytes(data, C.int(datalen)))
return 0
}
//export gogpgme_assuan_inquiry_callback
func gogpgme_assuan_inquiry_callback(handle unsafe.Pointer, cName *C.char, cArgs *C.char) C.gpgme_error_t {
name := C.GoString(cName)
args := C.GoString(cArgs)
c := callbackLookup(uintptr(handle)).(*AssuanInquireCallback)
if *c == nil {
return 0
}
(*c)(name, args)
return 0
}
//export gogpgme_assuan_status_callback
func gogpgme_assuan_status_callback(handle unsafe.Pointer, cStatus *C.char, cArgs *C.char) C.gpgme_error_t {
status := C.GoString(cStatus)
args := C.GoString(cArgs)
c := callbackLookup(uintptr(handle)).(*AssuanStatusCallback)
if *c == nil {
return 0
}
(*c)(status, args)
return 0
}
// ExportModeFlags defines how keys are exported from Export
type ExportModeFlags uint
const (
ExportModeExtern ExportModeFlags = C.GPGME_EXPORT_MODE_EXTERN
ExportModeMinimal ExportModeFlags = C.GPGME_EXPORT_MODE_MINIMAL
)
func (c *Context) Export(pattern string, mode ExportModeFlags, data *Data) error {
pat := C.CString(pattern)
defer C.free(unsafe.Pointer(pat))
err := handleError(C.gpgme_op_export(c.ctx, pat, C.gpgme_export_mode_t(mode), data.dh))
runtime.KeepAlive(c)
runtime.KeepAlive(data)
return err
} }
// ImportStatusFlags describes the type of ImportStatus.Status. The C API in gpgme.h simply uses "unsigned". // ImportStatusFlags describes the type of ImportStatus.Status. The C API in gpgme.h simply uses "unsigned".
@ -517,10 +687,14 @@ type ImportResult struct {
func (c *Context) Import(keyData *Data) (*ImportResult, error) { func (c *Context) Import(keyData *Data) (*ImportResult, error) {
err := handleError(C.gpgme_op_import(c.ctx, keyData.dh)) err := handleError(C.gpgme_op_import(c.ctx, keyData.dh))
runtime.KeepAlive(c)
runtime.KeepAlive(keyData)
if err != nil { if err != nil {
return nil, err return nil, err
} }
res := C.gpgme_op_import_result(c.ctx) res := C.gpgme_op_import_result(c.ctx)
runtime.KeepAlive(c)
// NOTE: c must be live as long as we are accessing res.
imports := []ImportStatus{} imports := []ImportStatus{}
for s := res.imports; s != nil; s = s.next { for s := res.imports; s != nil; s = s.next {
imports = append(imports, ImportStatus{ imports = append(imports, ImportStatus{
@ -529,7 +703,7 @@ func (c *Context) Import(keyData *Data) (*ImportResult, error) {
Status: ImportStatusFlags(s.status), Status: ImportStatusFlags(s.status),
}) })
} }
return &ImportResult{ importResult := &ImportResult{
Considered: int(res.considered), Considered: int(res.considered),
NoUserID: int(res.no_user_id), NoUserID: int(res.no_user_id),
Imported: int(res.imported), Imported: int(res.imported),
@ -544,11 +718,13 @@ func (c *Context) Import(keyData *Data) (*ImportResult, error) {
SecretUnchanged: int(res.secret_unchanged), SecretUnchanged: int(res.secret_unchanged),
NotImported: int(res.not_imported), NotImported: int(res.not_imported),
Imports: imports, Imports: imports,
}, nil }
runtime.KeepAlive(c) // for all accesses to res above
return importResult, nil
} }
type Key struct { type Key struct {
k C.gpgme_key_t k C.gpgme_key_t // WARNING: Call Runtime.KeepAlive(k) after ANY passing of k.k to C
} }
func newKey() *Key { func newKey() *Key {
@ -559,85 +735,122 @@ func newKey() *Key {
func (k *Key) Release() { func (k *Key) Release() {
C.gpgme_key_release(k.k) C.gpgme_key_release(k.k)
runtime.KeepAlive(k)
k.k = nil k.k = nil
} }
func (k *Key) Revoked() bool { func (k *Key) Revoked() bool {
return C.key_revoked(k.k) != 0 res := C.key_revoked(k.k) != 0
runtime.KeepAlive(k)
return res
} }
func (k *Key) Expired() bool { func (k *Key) Expired() bool {
return C.key_expired(k.k) != 0 res := C.key_expired(k.k) != 0
runtime.KeepAlive(k)
return res
} }
func (k *Key) Disabled() bool { func (k *Key) Disabled() bool {
return C.key_disabled(k.k) != 0 res := C.key_disabled(k.k) != 0
runtime.KeepAlive(k)
return res
} }
func (k *Key) Invalid() bool { func (k *Key) Invalid() bool {
return C.key_invalid(k.k) != 0 res := C.key_invalid(k.k) != 0
runtime.KeepAlive(k)
return res
} }
func (k *Key) CanEncrypt() bool { func (k *Key) CanEncrypt() bool {
return C.key_can_encrypt(k.k) != 0 res := C.key_can_encrypt(k.k) != 0
runtime.KeepAlive(k)
return res
} }
func (k *Key) CanSign() bool { func (k *Key) CanSign() bool {
return C.key_can_sign(k.k) != 0 res := C.key_can_sign(k.k) != 0
runtime.KeepAlive(k)
return res
} }
func (k *Key) CanCertify() bool { func (k *Key) CanCertify() bool {
return C.key_can_certify(k.k) != 0 res := C.key_can_certify(k.k) != 0
runtime.KeepAlive(k)
return res
} }
func (k *Key) Secret() bool { func (k *Key) Secret() bool {
return C.key_secret(k.k) != 0 res := C.key_secret(k.k) != 0
runtime.KeepAlive(k)
return res
} }
func (k *Key) CanAuthenticate() bool { func (k *Key) CanAuthenticate() bool {
return C.key_can_authenticate(k.k) != 0 res := C.key_can_authenticate(k.k) != 0
runtime.KeepAlive(k)
return res
} }
func (k *Key) IsQualified() bool { func (k *Key) IsQualified() bool {
return C.key_is_qualified(k.k) != 0 res := C.key_is_qualified(k.k) != 0
runtime.KeepAlive(k)
return res
} }
func (k *Key) Protocol() Protocol { func (k *Key) Protocol() Protocol {
return Protocol(k.k.protocol) res := Protocol(k.k.protocol)
runtime.KeepAlive(k)
return res
} }
func (k *Key) IssuerSerial() string { func (k *Key) IssuerSerial() string {
return C.GoString(k.k.issuer_serial) res := C.GoString(k.k.issuer_serial)
runtime.KeepAlive(k)
return res
} }
func (k *Key) IssuerName() string { func (k *Key) IssuerName() string {
return C.GoString(k.k.issuer_name) res := C.GoString(k.k.issuer_name)
runtime.KeepAlive(k)
return res
} }
func (k *Key) ChainID() string { func (k *Key) ChainID() string {
return C.GoString(k.k.chain_id) res := C.GoString(k.k.chain_id)
runtime.KeepAlive(k)
return res
} }
func (k *Key) OwnerTrust() Validity { func (k *Key) OwnerTrust() Validity {
return Validity(k.k.owner_trust) res := Validity(k.k.owner_trust)
runtime.KeepAlive(k)
return res
} }
func (k *Key) SubKeys() *SubKey { func (k *Key) SubKeys() *SubKey {
if k.k.subkeys == nil { subKeys := k.k.subkeys
runtime.KeepAlive(k)
if subKeys == nil {
return nil return nil
} }
return &SubKey{k: k.k.subkeys, parent: k} return &SubKey{k: subKeys, parent: k} // The parent: k reference ensures subKeys remains valid
} }
func (k *Key) UserIDs() *UserID { func (k *Key) UserIDs() *UserID {
if k.k.uids == nil { uids := k.k.uids
runtime.KeepAlive(k)
if uids == nil {
return nil return nil
} }
return &UserID{u: k.k.uids, parent: k} return &UserID{u: uids, parent: k} // The parent: k reference ensures uids remains valid
} }
func (k *Key) KeyListMode() KeyListMode { func (k *Key) KeyListMode() KeyListMode {
return KeyListMode(k.k.keylist_mode) res := KeyListMode(k.k.keylist_mode)
runtime.KeepAlive(k)
return res
} }
type SubKey struct { type SubKey struct {
@ -737,12 +950,3 @@ func (u *UserID) Comment() string {
func (u *UserID) Email() string { func (u *UserID) Email() string {
return C.GoString(u.u.email) return C.GoString(u.u.email)
} }
// This is somewhat of a horrible hack. We need to unset GPG_AGENT_INFO so that gpgme does not pass --use-agent to GPG.
// os.Unsetenv should be enough, but that only calls the underlying C library (which gpgme uses) if cgo is involved
// - and cgo can't be used in tests. So, provide this helper for test initialization.
func unsetenvGPGAgentInfo() {
v := C.CString("GPG_AGENT_INFO")
defer C.free(unsafe.Pointer(v))
C.unsetenv(v)
}

18
vendor/github.com/mtrmac/gpgme/unset_agent_info.go generated vendored Normal file
View File

@ -0,0 +1,18 @@
// +build !windows
package gpgme
// #include <stdlib.h>
import "C"
import (
"unsafe"
)
// This is somewhat of a horrible hack. We need to unset GPG_AGENT_INFO so that gpgme does not pass --use-agent to GPG.
// os.Unsetenv should be enough, but that only calls the underlying C library (which gpgme uses) if cgo is involved
// - and cgo can't be used in tests. So, provide this helper for test initialization.
func unsetenvGPGAgentInfo() {
v := C.CString("GPG_AGENT_INFO")
defer C.free(unsafe.Pointer(v))
C.unsetenv(v)
}

View File

@ -0,0 +1,14 @@
package gpgme
// #include <stdlib.h>
import "C"
import (
"unsafe"
)
// unsetenv is not available in mingw
func unsetenvGPGAgentInfo() {
v := C.CString("GPG_AGENT_INFO=")
defer C.free(unsafe.Pointer(v))
C.putenv(v)
}