787cbc
From c48714e522ea147e49b0d0dfddf58a9b47137055 Mon Sep 17 00:00:00 2001
787cbc
From: =?UTF-8?q?Miloslav=20Trma=C4=8D?= <mitr@redhat.com>
787cbc
Date: Thu, 20 Feb 2020 19:51:27 +0100
787cbc
Subject: [PATCH 1/3] Update to github.com/mtrmac/gpgme v0.1.2
787cbc
MIME-Version: 1.0
787cbc
Content-Type: text/plain; charset=UTF-8
787cbc
Content-Transfer-Encoding: 8bit
787cbc
787cbc
This fixes CVE-2020-8945 by incorporating proglottis/gpgme#23 .
787cbc
787cbc
Other changes included by the rebase:
787cbc
- Support for gpgme_off_t (~no-op on Linux)
787cbc
- Wrapping a few more GPGME functions (irrelevant if we don't call them)
787cbc
787cbc
Given how invasive the CVE fix is (affecting basically all binding
787cbc
code), it seems safer to just update the package (and be verifiably
787cbc
equivalent with upstream) than to backport and try to back out the few
787cbc
other changes.
787cbc
787cbc
Performed by
787cbc
$ go get github.com/mtrmac/gpgme@v0.1.2
787cbc
$ make vendor
787cbc
and manually backing out unrelated deletions of files (which Go 1.13 does
787cbc
but Go 1.11, used for testing the old version, does not).
787cbc
787cbc
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
787cbc
---
787cbc
 go.mod                                        |   1 +
787cbc
 go.sum                                        |   2 +
787cbc
 vendor/github.com/mtrmac/gpgme/.appveyor.yml  |  40 ++
787cbc
 vendor/github.com/mtrmac/gpgme/.travis.yml    |  32 ++
787cbc
 vendor/github.com/mtrmac/gpgme/data.go        |  18 +-
787cbc
 vendor/github.com/mtrmac/gpgme/go.mod         |   3 +
787cbc
 vendor/github.com/mtrmac/gpgme/go_gpgme.c     |  22 ++
787cbc
 vendor/github.com/mtrmac/gpgme/go_gpgme.h     |  12 +
787cbc
 vendor/github.com/mtrmac/gpgme/gpgme.go       | 346 ++++++++++++++----
787cbc
 .../mtrmac/gpgme/unset_agent_info.go          |  18 +
787cbc
 .../mtrmac/gpgme/unset_agent_info_windows.go  |  14 +
787cbc
 vendor/modules.txt                            |   2 +-
787cbc
 12 files changed, 432 insertions(+), 78 deletions(-)
787cbc
 create mode 100644 vendor/github.com/mtrmac/gpgme/.appveyor.yml
787cbc
 create mode 100644 vendor/github.com/mtrmac/gpgme/.travis.yml
787cbc
 create mode 100644 vendor/github.com/mtrmac/gpgme/go.mod
787cbc
 create mode 100644 vendor/github.com/mtrmac/gpgme/unset_agent_info.go
787cbc
 create mode 100644 vendor/github.com/mtrmac/gpgme/unset_agent_info_windows.go
787cbc
787cbc
diff --git a/go.mod b/go.mod
787cbc
index 788827569..3335d7573 100644
787cbc
--- a/go.mod
787cbc
+++ b/go.mod
787cbc
@@ -9,6 +9,7 @@ require (
787cbc
 	github.com/docker/docker v0.0.0-20180522102801-da99009bbb11
787cbc
 	github.com/dsnet/compress v0.0.1 // indirect
787cbc
 	github.com/go-check/check v0.0.0-20180628173108-788fd7840127
787cbc
+	github.com/mtrmac/gpgme v0.1.2 // indirect
787cbc
 	github.com/opencontainers/go-digest v1.0.0-rc1
787cbc
 	github.com/opencontainers/image-spec v1.0.2-0.20190823105129-775207bd45b6
787cbc
 	github.com/opencontainers/image-tools v0.0.0-20170926011501-6d941547fa1d
787cbc
diff --git a/go.sum b/go.sum
787cbc
index c04f6f3a2..3ad0f17de 100644
787cbc
--- a/go.sum
787cbc
+++ b/go.sum
787cbc
@@ -91,6 +91,8 @@ github.com/mistifyio/go-zfs v2.1.1+incompatible h1:gAMO1HM9xBRONLHHYnu5iFsOJUiJd
787cbc
 github.com/mistifyio/go-zfs v2.1.1+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4=
787cbc
 github.com/mtrmac/gpgme v0.0.0-20170102180018-b2432428689c h1:xa+eQWKuJ9MbB9FBL/eoNvDFvveAkz2LQoz8PzX7Q/4=
787cbc
 github.com/mtrmac/gpgme v0.0.0-20170102180018-b2432428689c/go.mod h1:GhAqVMEWnTcW2dxoD/SO3n2enrgWl3y6Dnx4m59GvcA=
787cbc
+github.com/mtrmac/gpgme v0.1.2 h1:dNOmvYmsrakgW7LcgiprD0yfRuQQe8/C8F6Z+zogO3s=
787cbc
+github.com/mtrmac/gpgme v0.1.2/go.mod h1:GYYHnGSuS7HK3zVS2n3y73y0okK/BeKzwnn5jgiVFNI=
787cbc
 github.com/mtrmac/image/v4 v4.0.0-20191002203927-a64d9d2717f4 h1:AE5cilZfrGtAgMg5Ed4c2Y2KczlOsMVZAK055sSq+gc=
787cbc
 github.com/mtrmac/image/v4 v4.0.0-20191002203927-a64d9d2717f4/go.mod h1:0ASJH1YgJiX/eqFZObqepgsvIA4XjCgpyfwn9pDGafA=
787cbc
 github.com/mtrmac/image/v4 v4.0.0-20191003181245-f4c983e93262 h1:HMUEnWU3OPT09JRFQLn8VTp3GfdfiEhDMAEhkdX8QnA=
787cbc
diff --git a/vendor/github.com/mtrmac/gpgme/.appveyor.yml b/vendor/github.com/mtrmac/gpgme/.appveyor.yml
787cbc
new file mode 100644
787cbc
index 000000000..2fdc09ab5
787cbc
--- /dev/null
787cbc
+++ b/vendor/github.com/mtrmac/gpgme/.appveyor.yml
787cbc
@@ -0,0 +1,40 @@
787cbc
+---
787cbc
+version: 0.{build}
787cbc
+platform: x86
787cbc
+branches:
787cbc
+  only:
787cbc
+    - master
787cbc
+
787cbc
+clone_folder: c:\gopath\src\github.com\proglottis\gpgme
787cbc
+
787cbc
+environment:   
787cbc
+  GOPATH: c:\gopath
787cbc
+  GOROOT: C:\go-x86
787cbc
+  CGO_LDFLAGS: -LC:\gpg\lib
787cbc
+  CGO_CFLAGS: -IC:\gpg\include
787cbc
+  GPG_DIR: C:\gpg
787cbc
+
787cbc
+install:
787cbc
+  - nuget install 7ZipCLI -ExcludeVersion
787cbc
+  - set PATH=%appveyor_build_folder%\7ZipCLI\tools;%PATH%
787cbc
+  - appveyor DownloadFile https://www.gnupg.org/ftp/gcrypt/binary/gnupg-w32-2.1.20_20170403.exe -FileName gnupg-w32-2.1.20_20170403.exe
787cbc
+  - 7z x -o%GPG_DIR% gnupg-w32-2.1.20_20170403.exe
787cbc
+  - copy "%GPG_DIR%\lib\libgpg-error.imp" "%GPG_DIR%\lib\libgpg-error.a"
787cbc
+  - copy "%GPG_DIR%\lib\libassuan.imp" "%GPG_DIR%\lib\libassuan.a"
787cbc
+  - copy "%GPG_DIR%\lib\libgpgme.imp" "%GPG_DIR%\lib\libgpgme.a"
787cbc
+  - set PATH=%GOPATH%\bin;%GOROOT%\bin;%GPG_DIR%\bin;C:\MinGW\bin;%PATH%
787cbc
+  - C:\cygwin\bin\sed -i 's/"GPG_AGENT_INFO"/"GPG_AGENT_INFO="/;s/C.unsetenv(v)/C.putenv(v)/' %APPVEYOR_BUILD_FOLDER%\gpgme.go
787cbc
+
787cbc
+test_script:
787cbc
+  - go test -v github.com/proglottis/gpgme
787cbc
+
787cbc
+
787cbc
+build_script:
787cbc
+  - go build -o example_decrypt.exe -i %APPVEYOR_BUILD_FOLDER%\examples\decrypt.go
787cbc
+  - go build -o example_encrypt.exe -i %APPVEYOR_BUILD_FOLDER%\examples\encrypt.go
787cbc
+
787cbc
+artifacts:
787cbc
+  - path: example_decrypt.exe
787cbc
+    name: decrypt example binary
787cbc
+  - path: example_encrypt.exe
787cbc
+    name: encrypt example binary
787cbc
\ No newline at end of file
787cbc
diff --git a/vendor/github.com/mtrmac/gpgme/.travis.yml b/vendor/github.com/mtrmac/gpgme/.travis.yml
787cbc
new file mode 100644
787cbc
index 000000000..619e33721
787cbc
--- /dev/null
787cbc
+++ b/vendor/github.com/mtrmac/gpgme/.travis.yml
787cbc
@@ -0,0 +1,32 @@
787cbc
+---
787cbc
+language: go
787cbc
+os:
787cbc
+  - linux
787cbc
+  - osx
787cbc
+  - windows
787cbc
+dist: xenial
787cbc
+sudo: false
787cbc
+
787cbc
+go:
787cbc
+  - 1.11
787cbc
+  - 1.12
787cbc
+  - 1.13
787cbc
+
787cbc
+addons:
787cbc
+  apt:
787cbc
+    packages:
787cbc
+    - libgpgme11-dev
787cbc
+  homebrew:
787cbc
+    packages:
787cbc
+    - gnupg
787cbc
+    - gnupg@1.4
787cbc
+    - gpgme
787cbc
+    update: true
787cbc
+
787cbc
+matrix:
787cbc
+  allow_failures:
787cbc
+    - os: windows
787cbc
+
787cbc
+before_install:
787cbc
+  - if [[ "$TRAVIS_OS_NAME" == "windows" ]]; then choco install msys2; fi
787cbc
+  - if [[ "$TRAVIS_OS_NAME" == "windows" ]]; then choco install gpg4win; fi
787cbc
diff --git a/vendor/github.com/mtrmac/gpgme/data.go b/vendor/github.com/mtrmac/gpgme/data.go
787cbc
index eebc97263..eee32c032 100644
787cbc
--- a/vendor/github.com/mtrmac/gpgme/data.go
787cbc
+++ b/vendor/github.com/mtrmac/gpgme/data.go
787cbc
@@ -50,25 +50,25 @@ func gogpgme_writefunc(handle, buffer unsafe.Pointer, size C.size_t) C.ssize_t {
787cbc
 }
787cbc
 
787cbc
 //export gogpgme_seekfunc
787cbc
-func gogpgme_seekfunc(handle unsafe.Pointer, offset C.off_t, whence C.int) C.off_t {
787cbc
+func gogpgme_seekfunc(handle unsafe.Pointer, offset C.gpgme_off_t, whence C.int) C.gpgme_off_t {
787cbc
 	d := callbackLookup(uintptr(handle)).(*Data)
787cbc
 	n, err := d.s.Seek(int64(offset), int(whence))
787cbc
 	if err != nil {
787cbc
 		C.gpgme_err_set_errno(C.EIO)
787cbc
 		return -1
787cbc
 	}
787cbc
-	return C.off_t(n)
787cbc
+	return C.gpgme_off_t(n)
787cbc
 }
787cbc
 
787cbc
 // The Data buffer used to communicate with GPGME
787cbc
 type Data struct {
787cbc
-	dh  C.gpgme_data_t
787cbc
+	dh  C.gpgme_data_t // WARNING: Call runtime.KeepAlive(d) after ANY passing of d.dh to C
787cbc
 	buf []byte
787cbc
 	cbs C.struct_gpgme_data_cbs
787cbc
 	r   io.Reader
787cbc
 	w   io.Writer
787cbc
 	s   io.Seeker
787cbc
-	cbc uintptr
787cbc
+	cbc uintptr // WARNING: Call runtime.KeepAlive(d) after ANY use of d.cbc in C (typically via d.dh)
787cbc
 }
787cbc
 
787cbc
 func newData() *Data {
787cbc
@@ -154,12 +154,14 @@ func (d *Data) Close() error {
787cbc
 		callbackDelete(d.cbc)
787cbc
 	}
787cbc
 	_, err := C.gpgme_data_release(d.dh)
787cbc
+	runtime.KeepAlive(d)
787cbc
 	d.dh = nil
787cbc
 	return err
787cbc
 }
787cbc
 
787cbc
 func (d *Data) Write(p []byte) (int, error) {
787cbc
 	n, err := C.gpgme_data_write(d.dh, unsafe.Pointer(&p[0]), C.size_t(len(p)))
787cbc
+	runtime.KeepAlive(d)
787cbc
 	if err != nil {
787cbc
 		return 0, err
787cbc
 	}
787cbc
@@ -171,6 +173,7 @@ func (d *Data) Write(p []byte) (int, error) {
787cbc
 
787cbc
 func (d *Data) Read(p []byte) (int, error) {
787cbc
 	n, err := C.gpgme_data_read(d.dh, unsafe.Pointer(&p[0]), C.size_t(len(p)))
787cbc
+	runtime.KeepAlive(d)
787cbc
 	if err != nil {
787cbc
 		return 0, err
787cbc
 	}
787cbc
@@ -181,11 +184,14 @@ func (d *Data) Read(p []byte) (int, error) {
787cbc
 }
787cbc
 
787cbc
 func (d *Data) Seek(offset int64, whence int) (int64, error) {
787cbc
-	n, err := C.gpgme_data_seek(d.dh, C.off_t(offset), C.int(whence))
787cbc
+	n, err := C.gogpgme_data_seek(d.dh, C.gpgme_off_t(offset), C.int(whence))
787cbc
+	runtime.KeepAlive(d)
787cbc
 	return int64(n), err
787cbc
 }
787cbc
 
787cbc
 // Name returns the associated filename if any
787cbc
 func (d *Data) Name() string {
787cbc
-	return C.GoString(C.gpgme_data_get_file_name(d.dh))
787cbc
+	res := C.GoString(C.gpgme_data_get_file_name(d.dh))
787cbc
+	runtime.KeepAlive(d)
787cbc
+	return res
787cbc
 }
787cbc
diff --git a/vendor/github.com/mtrmac/gpgme/go.mod b/vendor/github.com/mtrmac/gpgme/go.mod
787cbc
new file mode 100644
787cbc
index 000000000..3dd09c9fb
787cbc
--- /dev/null
787cbc
+++ b/vendor/github.com/mtrmac/gpgme/go.mod
787cbc
@@ -0,0 +1,3 @@
787cbc
+module github.com/mtrmac/gpgme
787cbc
+
787cbc
+go 1.11
787cbc
diff --git a/vendor/github.com/mtrmac/gpgme/go_gpgme.c b/vendor/github.com/mtrmac/gpgme/go_gpgme.c
787cbc
index b887574e0..00da3ab30 100644
787cbc
--- a/vendor/github.com/mtrmac/gpgme/go_gpgme.c
787cbc
+++ b/vendor/github.com/mtrmac/gpgme/go_gpgme.c
787cbc
@@ -8,6 +8,28 @@ void gogpgme_set_passphrase_cb(gpgme_ctx_t ctx, gpgme_passphrase_cb_t cb, uintpt
787cbc
 	gpgme_set_passphrase_cb(ctx, cb, (void *)handle);
787cbc
 }
787cbc
 
787cbc
+gpgme_off_t gogpgme_data_seek(gpgme_data_t dh, gpgme_off_t offset, int whence) {
787cbc
+	return gpgme_data_seek(dh, offset, whence);
787cbc
+}
787cbc
+
787cbc
+gpgme_error_t gogpgme_op_assuan_transact_ext(
787cbc
+		gpgme_ctx_t ctx,
787cbc
+		char* cmd,
787cbc
+		uintptr_t data_h,
787cbc
+		uintptr_t inquiry_h,
787cbc
+		uintptr_t status_h,
787cbc
+		gpgme_error_t *operr
787cbc
+	){
787cbc
+	return gpgme_op_assuan_transact_ext(
787cbc
+		ctx,
787cbc
+		cmd,
787cbc
+		(gpgme_assuan_data_cb_t)    gogpgme_assuan_data_callback,    (void *)data_h,
787cbc
+		(gpgme_assuan_inquire_cb_t) gogpgme_assuan_inquiry_callback, (void *)inquiry_h,
787cbc
+		(gpgme_assuan_status_cb_t)  gogpgme_assuan_status_callback,  (void *)status_h,
787cbc
+		operr
787cbc
+	);
787cbc
+}
787cbc
+
787cbc
 unsigned int key_revoked(gpgme_key_t k) {
787cbc
 	return k->revoked;
787cbc
 }
787cbc
diff --git a/vendor/github.com/mtrmac/gpgme/go_gpgme.h b/vendor/github.com/mtrmac/gpgme/go_gpgme.h
787cbc
index a3678b127..d4826ab36 100644
787cbc
--- a/vendor/github.com/mtrmac/gpgme/go_gpgme.h
787cbc
+++ b/vendor/github.com/mtrmac/gpgme/go_gpgme.h
787cbc
@@ -6,12 +6,24 @@
787cbc
 
787cbc
 #include <gpgme.h>
787cbc
 
787cbc
+/* GPGME_VERSION_NUMBER was introduced in 1.4.0 */
787cbc
+#if !defined(GPGME_VERSION_NUMBER) || GPGME_VERSION_NUMBER < 0x010402
787cbc
+typedef off_t gpgme_off_t; /* Introduced in 1.4.2 */
787cbc
+#endif
787cbc
+
787cbc
 extern ssize_t gogpgme_readfunc(void *handle, void *buffer, size_t size);
787cbc
 extern ssize_t gogpgme_writefunc(void *handle, void *buffer, size_t size);
787cbc
 extern off_t gogpgme_seekfunc(void *handle, off_t offset, int whence);
787cbc
 extern gpgme_error_t gogpgme_passfunc(void *hook, char *uid_hint, char *passphrase_info, int prev_was_bad, int fd);
787cbc
 extern gpgme_error_t gogpgme_data_new_from_cbs(gpgme_data_t *dh, gpgme_data_cbs_t cbs, uintptr_t handle);
787cbc
 extern void gogpgme_set_passphrase_cb(gpgme_ctx_t ctx, gpgme_passphrase_cb_t cb, uintptr_t handle);
787cbc
+extern gpgme_off_t gogpgme_data_seek(gpgme_data_t dh, gpgme_off_t offset, int whence);
787cbc
+
787cbc
+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);
787cbc
+
787cbc
+extern gpgme_error_t gogpgme_assuan_data_callback(void *opaque, void* data, size_t datalen );
787cbc
+extern gpgme_error_t gogpgme_assuan_inquiry_callback(void *opaque, char* name, char* args);
787cbc
+extern gpgme_error_t gogpgme_assuan_status_callback(void *opaque, char* status, char* args);
787cbc
 
787cbc
 extern unsigned int key_revoked(gpgme_key_t k);
787cbc
 extern unsigned int key_expired(gpgme_key_t k);
787cbc
diff --git a/vendor/github.com/mtrmac/gpgme/gpgme.go b/vendor/github.com/mtrmac/gpgme/gpgme.go
787cbc
index 20aad737c..c19b9aebc 100644
787cbc
--- a/vendor/github.com/mtrmac/gpgme/gpgme.go
787cbc
+++ b/vendor/github.com/mtrmac/gpgme/gpgme.go
787cbc
@@ -7,7 +7,6 @@ package gpgme
787cbc
 // #include <gpgme.h>
787cbc
 // #include "go_gpgme.h"
787cbc
 import "C"
787cbc
-
787cbc
 import (
787cbc
 	"fmt"
787cbc
 	"io"
787cbc
@@ -48,9 +47,8 @@ const (
787cbc
 	ProtocolAssuan   Protocol = C.GPGME_PROTOCOL_ASSUAN
787cbc
 	ProtocolG13      Protocol = C.GPGME_PROTOCOL_G13
787cbc
 	ProtocolUIServer Protocol = C.GPGME_PROTOCOL_UISERVER
787cbc
-	// ProtocolSpawn    Protocol = C.GPGME_PROTOCOL_SPAWN // Unavailable in 1.4.3
787cbc
-	ProtocolDefault Protocol = C.GPGME_PROTOCOL_DEFAULT
787cbc
-	ProtocolUnknown Protocol = C.GPGME_PROTOCOL_UNKNOWN
787cbc
+	ProtocolDefault  Protocol = C.GPGME_PROTOCOL_DEFAULT
787cbc
+	ProtocolUnknown  Protocol = C.GPGME_PROTOCOL_UNKNOWN
787cbc
 )
787cbc
 
787cbc
 type PinEntryMode int
787cbc
@@ -70,7 +68,6 @@ const (
787cbc
 	EncryptNoEncryptTo EncryptFlag = C.GPGME_ENCRYPT_NO_ENCRYPT_TO
787cbc
 	EncryptPrepare     EncryptFlag = C.GPGME_ENCRYPT_PREPARE
787cbc
 	EncryptExceptSign  EncryptFlag = C.GPGME_ENCRYPT_EXPECT_SIGN
787cbc
-	// EncryptNoCompress  EncryptFlag = C.GPGME_ENCRYPT_NO_COMPRESS // Unavailable in 1.4.3
787cbc
 )
787cbc
 
787cbc
 type HashAlgo int
787cbc
@@ -84,7 +81,6 @@ const (
787cbc
 	KeyListModeExtern       KeyListMode = C.GPGME_KEYLIST_MODE_EXTERN
787cbc
 	KeyListModeSigs         KeyListMode = C.GPGME_KEYLIST_MODE_SIGS
787cbc
 	KeyListModeSigNotations KeyListMode = C.GPGME_KEYLIST_MODE_SIG_NOTATIONS
787cbc
-	// KeyListModeWithSecret   KeyListMode = C.GPGME_KEYLIST_MODE_WITH_SECRET // Unavailable in 1.4.3
787cbc
 	KeyListModeEphemeral    KeyListMode = C.GPGME_KEYLIST_MODE_EPHEMERAL
787cbc
 	KeyListModeModeValidate KeyListMode = C.GPGME_KEYLIST_MODE_VALIDATE
787cbc
 )
787cbc
@@ -168,39 +164,60 @@ func EngineCheckVersion(p Protocol) error {
787cbc
 }
787cbc
 
787cbc
 type EngineInfo struct {
787cbc
-	info C.gpgme_engine_info_t
787cbc
+	next            *EngineInfo
787cbc
+	protocol        Protocol
787cbc
+	fileName        string
787cbc
+	homeDir         string
787cbc
+	version         string
787cbc
+	requiredVersion string
787cbc
 }
787cbc
 
787cbc
-func (e *EngineInfo) Next() *EngineInfo {
787cbc
-	if e.info.next == nil {
787cbc
-		return nil
787cbc
+func copyEngineInfo(info C.gpgme_engine_info_t) *EngineInfo {
787cbc
+	res := &EngineInfo{
787cbc
+		next:            nil,
787cbc
+		protocol:        Protocol(info.protocol),
787cbc
+		fileName:        C.GoString(info.file_name),
787cbc
+		homeDir:         C.GoString(info.home_dir),
787cbc
+		version:         C.GoString(info.version),
787cbc
+		requiredVersion: C.GoString(info.req_version),
787cbc
+	}
787cbc
+	if info.next != nil {
787cbc
+		res.next = copyEngineInfo(info.next)
787cbc
 	}
787cbc
-	return &EngineInfo{info: e.info.next}
787cbc
+	return res
787cbc
+}
787cbc
+
787cbc
+func (e *EngineInfo) Next() *EngineInfo {
787cbc
+	return e.next
787cbc
 }
787cbc
 
787cbc
 func (e *EngineInfo) Protocol() Protocol {
787cbc
-	return Protocol(e.info.protocol)
787cbc
+	return e.protocol
787cbc
 }
787cbc
 
787cbc
 func (e *EngineInfo) FileName() string {
787cbc
-	return C.GoString(e.info.file_name)
787cbc
+	return e.fileName
787cbc
 }
787cbc
 
787cbc
 func (e *EngineInfo) Version() string {
787cbc
-	return C.GoString(e.info.version)
787cbc
+	return e.version
787cbc
 }
787cbc
 
787cbc
 func (e *EngineInfo) RequiredVersion() string {
787cbc
-	return C.GoString(e.info.req_version)
787cbc
+	return e.requiredVersion
787cbc
 }
787cbc
 
787cbc
 func (e *EngineInfo) HomeDir() string {
787cbc
-	return C.GoString(e.info.home_dir)
787cbc
+	return e.homeDir
787cbc
 }
787cbc
 
787cbc
 func GetEngineInfo() (*EngineInfo, error) {
787cbc
-	info := &EngineInfo{}
787cbc
-	return info, handleError(C.gpgme_get_engine_info(&info.info))
787cbc
+	var cInfo C.gpgme_engine_info_t
787cbc
+	err := handleError(C.gpgme_get_engine_info(&cInfo))
787cbc
+	if err != nil {
787cbc
+		return nil, err
787cbc
+	}
787cbc
+	return copyEngineInfo(cInfo), nil // It is up to the caller not to invalidate cInfo concurrently until this is done.
787cbc
 }
787cbc
 
787cbc
 func SetEngineInfo(proto Protocol, fileName, homeDir string) error {
787cbc
@@ -261,9 +278,9 @@ type Context struct {
787cbc
 	KeyError error
787cbc
 
787cbc
 	callback Callback
787cbc
-	cbc      uintptr
787cbc
+	cbc      uintptr // WARNING: Call runtime.KeepAlive(c) after ANY use of c.cbc in C (typically via c.ctx)
787cbc
 
787cbc
-	ctx C.gpgme_ctx_t
787cbc
+	ctx C.gpgme_ctx_t // WARNING: Call runtime.KeepAlive(c) after ANY passing of c.ctx to C
787cbc
 }
787cbc
 
787cbc
 func New() (*Context, error) {
787cbc
@@ -281,49 +298,68 @@ func (c *Context) Release() {
787cbc
 		callbackDelete(c.cbc)
787cbc
 	}
787cbc
 	C.gpgme_release(c.ctx)
787cbc
+	runtime.KeepAlive(c)
787cbc
 	c.ctx = nil
787cbc
 }
787cbc
 
787cbc
 func (c *Context) SetArmor(yes bool) {
787cbc
 	C.gpgme_set_armor(c.ctx, cbool(yes))
787cbc
+	runtime.KeepAlive(c)
787cbc
 }
787cbc
 
787cbc
 func (c *Context) Armor() bool {
787cbc
-	return C.gpgme_get_armor(c.ctx) != 0
787cbc
+	res := C.gpgme_get_armor(c.ctx) != 0
787cbc
+	runtime.KeepAlive(c)
787cbc
+	return res
787cbc
 }
787cbc
 
787cbc
 func (c *Context) SetTextMode(yes bool) {
787cbc
 	C.gpgme_set_textmode(c.ctx, cbool(yes))
787cbc
+	runtime.KeepAlive(c)
787cbc
 }
787cbc
 
787cbc
 func (c *Context) TextMode() bool {
787cbc
-	return C.gpgme_get_textmode(c.ctx) != 0
787cbc
+	res := C.gpgme_get_textmode(c.ctx) != 0
787cbc
+	runtime.KeepAlive(c)
787cbc
+	return res
787cbc
 }
787cbc
 
787cbc
 func (c *Context) SetProtocol(p Protocol) error {
787cbc
-	return handleError(C.gpgme_set_protocol(c.ctx, C.gpgme_protocol_t(p)))
787cbc
+	err := handleError(C.gpgme_set_protocol(c.ctx, C.gpgme_protocol_t(p)))
787cbc
+	runtime.KeepAlive(c)
787cbc
+	return err
787cbc
 }
787cbc
 
787cbc
 func (c *Context) Protocol() Protocol {
787cbc
-	return Protocol(C.gpgme_get_protocol(c.ctx))
787cbc
+	res := Protocol(C.gpgme_get_protocol(c.ctx))
787cbc
+	runtime.KeepAlive(c)
787cbc
+	return res
787cbc
 }
787cbc
 
787cbc
 func (c *Context) SetKeyListMode(m KeyListMode) error {
787cbc
-	return handleError(C.gpgme_set_keylist_mode(c.ctx, C.gpgme_keylist_mode_t(m)))
787cbc
+	err := handleError(C.gpgme_set_keylist_mode(c.ctx, C.gpgme_keylist_mode_t(m)))
787cbc
+	runtime.KeepAlive(c)
787cbc
+	return err
787cbc
 }
787cbc
 
787cbc
 func (c *Context) KeyListMode() KeyListMode {
787cbc
-	return KeyListMode(C.gpgme_get_keylist_mode(c.ctx))
787cbc
+	res := KeyListMode(C.gpgme_get_keylist_mode(c.ctx))
787cbc
+	runtime.KeepAlive(c)
787cbc
+	return res
787cbc
 }
787cbc
 
787cbc
 // Unavailable in 1.3.2:
787cbc
 // func (c *Context) SetPinEntryMode(m PinEntryMode) error {
787cbc
-// 	return handleError(C.gpgme_set_pinentry_mode(c.ctx, C.gpgme_pinentry_mode_t(m)))
787cbc
+// 	err := handleError(C.gpgme_set_pinentry_mode(c.ctx, C.gpgme_pinentry_mode_t(m)))
787cbc
+// 	runtime.KeepAlive(c)
787cbc
+// 	return err
787cbc
 // }
787cbc
 
787cbc
 // Unavailable in 1.3.2:
787cbc
 // func (c *Context) PinEntryMode() PinEntryMode {
787cbc
-// 	return PinEntryMode(C.gpgme_get_pinentry_mode(c.ctx))
787cbc
+// 	res := PinEntryMode(C.gpgme_get_pinentry_mode(c.ctx))
787cbc
+// 	runtime.KeepAlive(c)
787cbc
+// 	return res
787cbc
 // }
787cbc
 
787cbc
 func (c *Context) SetCallback(callback Callback) error {
787cbc
@@ -340,11 +376,17 @@ func (c *Context) SetCallback(callback Callback) error {
787cbc
 		c.cbc = 0
787cbc
 		_, err = C.gogpgme_set_passphrase_cb(c.ctx, nil, 0)
787cbc
 	}
787cbc
+	runtime.KeepAlive(c)
787cbc
 	return err
787cbc
 }
787cbc
 
787cbc
 func (c *Context) EngineInfo() *EngineInfo {
787cbc
-	return &EngineInfo{info: C.gpgme_ctx_get_engine_info(c.ctx)}
787cbc
+	cInfo := C.gpgme_ctx_get_engine_info(c.ctx)
787cbc
+	runtime.KeepAlive(c)
787cbc
+	// NOTE: c must be live as long as we are accessing cInfo.
787cbc
+	res := copyEngineInfo(cInfo)
787cbc
+	runtime.KeepAlive(c) // for accesses to cInfo
787cbc
+	return res
787cbc
 }
787cbc
 
787cbc
 func (c *Context) SetEngineInfo(proto Protocol, fileName, homeDir string) error {
787cbc
@@ -357,19 +399,23 @@ func (c *Context) SetEngineInfo(proto Protocol, fileName, homeDir string) error
787cbc
 		chome = C.CString(homeDir)
787cbc
 		defer C.free(unsafe.Pointer(chome))
787cbc
 	}
787cbc
-	return handleError(C.gpgme_ctx_set_engine_info(c.ctx, C.gpgme_protocol_t(proto), cfn, chome))
787cbc
+	err := handleError(C.gpgme_ctx_set_engine_info(c.ctx, C.gpgme_protocol_t(proto), cfn, chome))
787cbc
+	runtime.KeepAlive(c)
787cbc
+	return err
787cbc
 }
787cbc
 
787cbc
 func (c *Context) KeyListStart(pattern string, secretOnly bool) error {
787cbc
 	cpattern := C.CString(pattern)
787cbc
 	defer C.free(unsafe.Pointer(cpattern))
787cbc
-	err := C.gpgme_op_keylist_start(c.ctx, cpattern, cbool(secretOnly))
787cbc
-	return handleError(err)
787cbc
+	err := handleError(C.gpgme_op_keylist_start(c.ctx, cpattern, cbool(secretOnly)))
787cbc
+	runtime.KeepAlive(c)
787cbc
+	return err
787cbc
 }
787cbc
 
787cbc
 func (c *Context) KeyListNext() bool {
787cbc
 	c.Key = newKey()
787cbc
 	err := handleError(C.gpgme_op_keylist_next(c.ctx, &c.Key.k))
787cbc
+	runtime.KeepAlive(c) // implies runtime.KeepAlive(c.Key)
787cbc
 	if err != nil {
787cbc
 		if e, ok := err.(Error); ok && e.Code() == ErrorEOF {
787cbc
 			c.KeyError = nil
787cbc
@@ -383,7 +429,9 @@ func (c *Context) KeyListNext() bool {
787cbc
 }
787cbc
 
787cbc
 func (c *Context) KeyListEnd() error {
787cbc
-	return handleError(C.gpgme_op_keylist_end(c.ctx))
787cbc
+	err := handleError(C.gpgme_op_keylist_end(c.ctx))
787cbc
+	runtime.KeepAlive(c)
787cbc
+	return err
787cbc
 }
787cbc
 
787cbc
 func (c *Context) GetKey(fingerprint string, secret bool) (*Key, error) {
787cbc
@@ -391,7 +439,11 @@ func (c *Context) GetKey(fingerprint string, secret bool) (*Key, error) {
787cbc
 	cfpr := C.CString(fingerprint)
787cbc
 	defer C.free(unsafe.Pointer(cfpr))
787cbc
 	err := handleError(C.gpgme_get_key(c.ctx, cfpr, &key.k, cbool(secret)))
787cbc
-	if e, ok := err.(Error); key.k == nil && ok && e.Code() == ErrorEOF {
787cbc
+	runtime.KeepAlive(c)
787cbc
+	runtime.KeepAlive(key)
787cbc
+	keyKIsNil := key.k == nil
787cbc
+	runtime.KeepAlive(key)
787cbc
+	if e, ok := err.(Error); keyKIsNil && ok && e.Code() == ErrorEOF {
787cbc
 		return nil, fmt.Errorf("key %q not found", fingerprint)
787cbc
 	}
787cbc
 	if err != nil {
787cbc
@@ -401,11 +453,19 @@ func (c *Context) GetKey(fingerprint string, secret bool) (*Key, error) {
787cbc
 }
787cbc
 
787cbc
 func (c *Context) Decrypt(ciphertext, plaintext *Data) error {
787cbc
-	return handleError(C.gpgme_op_decrypt(c.ctx, ciphertext.dh, plaintext.dh))
787cbc
+	err := handleError(C.gpgme_op_decrypt(c.ctx, ciphertext.dh, plaintext.dh))
787cbc
+	runtime.KeepAlive(c)
787cbc
+	runtime.KeepAlive(ciphertext)
787cbc
+	runtime.KeepAlive(plaintext)
787cbc
+	return err
787cbc
 }
787cbc
 
787cbc
 func (c *Context) DecryptVerify(ciphertext, plaintext *Data) error {
787cbc
-	return handleError(C.gpgme_op_decrypt_verify(c.ctx, ciphertext.dh, plaintext.dh))
787cbc
+	err := handleError(C.gpgme_op_decrypt_verify(c.ctx, ciphertext.dh, plaintext.dh))
787cbc
+	runtime.KeepAlive(c)
787cbc
+	runtime.KeepAlive(ciphertext)
787cbc
+	runtime.KeepAlive(plaintext)
787cbc
+	return err
787cbc
 }
787cbc
 
787cbc
 type Signature struct {
787cbc
@@ -432,10 +492,20 @@ func (c *Context) Verify(sig, signedText, plain *Data) (string, []Signature, err
787cbc
 		plainPtr = plain.dh
787cbc
 	}
787cbc
 	err := handleError(C.gpgme_op_verify(c.ctx, sig.dh, signedTextPtr, plainPtr))
787cbc
+	runtime.KeepAlive(c)
787cbc
+	runtime.KeepAlive(sig)
787cbc
+	if signedText != nil {
787cbc
+		runtime.KeepAlive(signedText)
787cbc
+	}
787cbc
+	if plain != nil {
787cbc
+		runtime.KeepAlive(plain)
787cbc
+	}
787cbc
 	if err != nil {
787cbc
 		return "", nil, err
787cbc
 	}
787cbc
 	res := C.gpgme_op_verify_result(c.ctx)
787cbc
+	runtime.KeepAlive(c)
787cbc
+	// NOTE: c must be live as long as we are accessing res.
787cbc
 	sigs := []Signature{}
787cbc
 	for s := res.signatures; s != nil; s = s.next {
787cbc
 		sig := Signature{
787cbc
@@ -455,7 +525,9 @@ func (c *Context) Verify(sig, signedText, plain *Data) (string, []Signature, err
787cbc
 		}
787cbc
 		sigs = append(sigs, sig)
787cbc
 	}
787cbc
-	return C.GoString(res.file_name), sigs, nil
787cbc
+	fileName := C.GoString(res.file_name)
787cbc
+	runtime.KeepAlive(c) // for all accesses to res above
787cbc
+	return fileName, sigs, nil
787cbc
 }
787cbc
 
787cbc
 func (c *Context) Encrypt(recipients []*Key, flags EncryptFlag, plaintext, ciphertext *Data) error {
787cbc
@@ -467,18 +539,116 @@ func (c *Context) Encrypt(recipients []*Key, flags EncryptFlag, plaintext, ciphe
787cbc
 		*ptr = recipients[i].k
787cbc
 	}
787cbc
 	err := C.gpgme_op_encrypt(c.ctx, (*C.gpgme_key_t)(recp), C.gpgme_encrypt_flags_t(flags), plaintext.dh, ciphertext.dh)
787cbc
+	runtime.KeepAlive(c)
787cbc
+	runtime.KeepAlive(recipients)
787cbc
+	runtime.KeepAlive(plaintext)
787cbc
+	runtime.KeepAlive(ciphertext)
787cbc
 	return handleError(err)
787cbc
 }
787cbc
 
787cbc
 func (c *Context) Sign(signers []*Key, plain, sig *Data, mode SigMode) error {
787cbc
 	C.gpgme_signers_clear(c.ctx)
787cbc
+	runtime.KeepAlive(c)
787cbc
 	for _, k := range signers {
787cbc
-		if err := handleError(C.gpgme_signers_add(c.ctx, k.k)); err != nil {
787cbc
+		err := handleError(C.gpgme_signers_add(c.ctx, k.k))
787cbc
+		runtime.KeepAlive(c)
787cbc
+		runtime.KeepAlive(k)
787cbc
+		if err != nil {
787cbc
 			C.gpgme_signers_clear(c.ctx)
787cbc
+			runtime.KeepAlive(c)
787cbc
 			return err
787cbc
 		}
787cbc
 	}
787cbc
-	return handleError(C.gpgme_op_sign(c.ctx, plain.dh, sig.dh, C.gpgme_sig_mode_t(mode)))
787cbc
+	err := handleError(C.gpgme_op_sign(c.ctx, plain.dh, sig.dh, C.gpgme_sig_mode_t(mode)))
787cbc
+	runtime.KeepAlive(c)
787cbc
+	runtime.KeepAlive(plain)
787cbc
+	runtime.KeepAlive(sig)
787cbc
+	return err
787cbc
+}
787cbc
+
787cbc
+type AssuanDataCallback func(data []byte) error
787cbc
+type AssuanInquireCallback func(name, args string) error
787cbc
+type AssuanStatusCallback func(status, args string) error
787cbc
+
787cbc
+// AssuanSend sends a raw Assuan command to gpg-agent
787cbc
+func (c *Context) AssuanSend(
787cbc
+	cmd string,
787cbc
+	data AssuanDataCallback,
787cbc
+	inquiry AssuanInquireCallback,
787cbc
+	status AssuanStatusCallback,
787cbc
+) error {
787cbc
+	var operr C.gpgme_error_t
787cbc
+
787cbc
+	dataPtr := callbackAdd(&data)
787cbc
+	inquiryPtr := callbackAdd(&inquiry)
787cbc
+	statusPtr := callbackAdd(&status)
787cbc
+	cmdCStr := C.CString(cmd)
787cbc
+	defer C.free(unsafe.Pointer(cmdCStr))
787cbc
+	err := C.gogpgme_op_assuan_transact_ext(
787cbc
+		c.ctx,
787cbc
+		cmdCStr,
787cbc
+		C.uintptr_t(dataPtr),
787cbc
+		C.uintptr_t(inquiryPtr),
787cbc
+		C.uintptr_t(statusPtr),
787cbc
+		&operr,
787cbc
+	)
787cbc
+	runtime.KeepAlive(c)
787cbc
+
787cbc
+	if handleError(operr) != nil {
787cbc
+		return handleError(operr)
787cbc
+	}
787cbc
+	return handleError(err)
787cbc
+}
787cbc
+
787cbc
+//export gogpgme_assuan_data_callback
787cbc
+func gogpgme_assuan_data_callback(handle unsafe.Pointer, data unsafe.Pointer, datalen C.size_t) C.gpgme_error_t {
787cbc
+	c := callbackLookup(uintptr(handle)).(*AssuanDataCallback)
787cbc
+	if *c == nil {
787cbc
+		return 0
787cbc
+	}
787cbc
+	(*c)(C.GoBytes(data, C.int(datalen)))
787cbc
+	return 0
787cbc
+}
787cbc
+
787cbc
+//export gogpgme_assuan_inquiry_callback
787cbc
+func gogpgme_assuan_inquiry_callback(handle unsafe.Pointer, cName *C.char, cArgs *C.char) C.gpgme_error_t {
787cbc
+	name := C.GoString(cName)
787cbc
+	args := C.GoString(cArgs)
787cbc
+	c := callbackLookup(uintptr(handle)).(*AssuanInquireCallback)
787cbc
+	if *c == nil {
787cbc
+		return 0
787cbc
+	}
787cbc
+	(*c)(name, args)
787cbc
+	return 0
787cbc
+}
787cbc
+
787cbc
+//export gogpgme_assuan_status_callback
787cbc
+func gogpgme_assuan_status_callback(handle unsafe.Pointer, cStatus *C.char, cArgs *C.char) C.gpgme_error_t {
787cbc
+	status := C.GoString(cStatus)
787cbc
+	args := C.GoString(cArgs)
787cbc
+	c := callbackLookup(uintptr(handle)).(*AssuanStatusCallback)
787cbc
+	if *c == nil {
787cbc
+		return 0
787cbc
+	}
787cbc
+	(*c)(status, args)
787cbc
+	return 0
787cbc
+}
787cbc
+
787cbc
+// ExportModeFlags defines how keys are exported from Export
787cbc
+type ExportModeFlags uint
787cbc
+
787cbc
+const (
787cbc
+	ExportModeExtern  ExportModeFlags = C.GPGME_EXPORT_MODE_EXTERN
787cbc
+	ExportModeMinimal ExportModeFlags = C.GPGME_EXPORT_MODE_MINIMAL
787cbc
+)
787cbc
+
787cbc
+func (c *Context) Export(pattern string, mode ExportModeFlags, data *Data) error {
787cbc
+	pat := C.CString(pattern)
787cbc
+	defer C.free(unsafe.Pointer(pat))
787cbc
+	err := handleError(C.gpgme_op_export(c.ctx, pat, C.gpgme_export_mode_t(mode), data.dh))
787cbc
+	runtime.KeepAlive(c)
787cbc
+	runtime.KeepAlive(data)
787cbc
+	return err
787cbc
 }
787cbc
 
787cbc
 // ImportStatusFlags describes the type of ImportStatus.Status. The C API in gpgme.h simply uses "unsigned".
787cbc
@@ -517,10 +687,14 @@ type ImportResult struct {
787cbc
 
787cbc
 func (c *Context) Import(keyData *Data) (*ImportResult, error) {
787cbc
 	err := handleError(C.gpgme_op_import(c.ctx, keyData.dh))
787cbc
+	runtime.KeepAlive(c)
787cbc
+	runtime.KeepAlive(keyData)
787cbc
 	if err != nil {
787cbc
 		return nil, err
787cbc
 	}
787cbc
 	res := C.gpgme_op_import_result(c.ctx)
787cbc
+	runtime.KeepAlive(c)
787cbc
+	// NOTE: c must be live as long as we are accessing res.
787cbc
 	imports := []ImportStatus{}
787cbc
 	for s := res.imports; s != nil; s = s.next {
787cbc
 		imports = append(imports, ImportStatus{
787cbc
@@ -529,7 +703,7 @@ func (c *Context) Import(keyData *Data) (*ImportResult, error) {
787cbc
 			Status:      ImportStatusFlags(s.status),
787cbc
 		})
787cbc
 	}
787cbc
-	return &ImportResult{
787cbc
+	importResult := &ImportResult{
787cbc
 		Considered:      int(res.considered),
787cbc
 		NoUserID:        int(res.no_user_id),
787cbc
 		Imported:        int(res.imported),
787cbc
@@ -544,11 +718,13 @@ func (c *Context) Import(keyData *Data) (*ImportResult, error) {
787cbc
 		SecretUnchanged: int(res.secret_unchanged),
787cbc
 		NotImported:     int(res.not_imported),
787cbc
 		Imports:         imports,
787cbc
-	}, nil
787cbc
+	}
787cbc
+	runtime.KeepAlive(c) // for all accesses to res above
787cbc
+	return importResult, nil
787cbc
 }
787cbc
 
787cbc
 type Key struct {
787cbc
-	k C.gpgme_key_t
787cbc
+	k C.gpgme_key_t // WARNING: Call Runtime.KeepAlive(k) after ANY passing of k.k to C
787cbc
 }
787cbc
 
787cbc
 func newKey() *Key {
787cbc
@@ -559,85 +735,122 @@ func newKey() *Key {
787cbc
 
787cbc
 func (k *Key) Release() {
787cbc
 	C.gpgme_key_release(k.k)
787cbc
+	runtime.KeepAlive(k)
787cbc
 	k.k = nil
787cbc
 }
787cbc
 
787cbc
 func (k *Key) Revoked() bool {
787cbc
-	return C.key_revoked(k.k) != 0
787cbc
+	res := C.key_revoked(k.k) != 0
787cbc
+	runtime.KeepAlive(k)
787cbc
+	return res
787cbc
 }
787cbc
 
787cbc
 func (k *Key) Expired() bool {
787cbc
-	return C.key_expired(k.k) != 0
787cbc
+	res := C.key_expired(k.k) != 0
787cbc
+	runtime.KeepAlive(k)
787cbc
+	return res
787cbc
 }
787cbc
 
787cbc
 func (k *Key) Disabled() bool {
787cbc
-	return C.key_disabled(k.k) != 0
787cbc
+	res := C.key_disabled(k.k) != 0
787cbc
+	runtime.KeepAlive(k)
787cbc
+	return res
787cbc
 }
787cbc
 
787cbc
 func (k *Key) Invalid() bool {
787cbc
-	return C.key_invalid(k.k) != 0
787cbc
+	res := C.key_invalid(k.k) != 0
787cbc
+	runtime.KeepAlive(k)
787cbc
+	return res
787cbc
 }
787cbc
 
787cbc
 func (k *Key) CanEncrypt() bool {
787cbc
-	return C.key_can_encrypt(k.k) != 0
787cbc
+	res := C.key_can_encrypt(k.k) != 0
787cbc
+	runtime.KeepAlive(k)
787cbc
+	return res
787cbc
 }
787cbc
 
787cbc
 func (k *Key) CanSign() bool {
787cbc
-	return C.key_can_sign(k.k) != 0
787cbc
+	res := C.key_can_sign(k.k) != 0
787cbc
+	runtime.KeepAlive(k)
787cbc
+	return res
787cbc
 }
787cbc
 
787cbc
 func (k *Key) CanCertify() bool {
787cbc
-	return C.key_can_certify(k.k) != 0
787cbc
+	res := C.key_can_certify(k.k) != 0
787cbc
+	runtime.KeepAlive(k)
787cbc
+	return res
787cbc
 }
787cbc
 
787cbc
 func (k *Key) Secret() bool {
787cbc
-	return C.key_secret(k.k) != 0
787cbc
+	res := C.key_secret(k.k) != 0
787cbc
+	runtime.KeepAlive(k)
787cbc
+	return res
787cbc
 }
787cbc
 
787cbc
 func (k *Key) CanAuthenticate() bool {
787cbc
-	return C.key_can_authenticate(k.k) != 0
787cbc
+	res := C.key_can_authenticate(k.k) != 0
787cbc
+	runtime.KeepAlive(k)
787cbc
+	return res
787cbc
 }
787cbc
 
787cbc
 func (k *Key) IsQualified() bool {
787cbc
-	return C.key_is_qualified(k.k) != 0
787cbc
+	res := C.key_is_qualified(k.k) != 0
787cbc
+	runtime.KeepAlive(k)
787cbc
+	return res
787cbc
 }
787cbc
 
787cbc
 func (k *Key) Protocol() Protocol {
787cbc
-	return Protocol(k.k.protocol)
787cbc
+	res := Protocol(k.k.protocol)
787cbc
+	runtime.KeepAlive(k)
787cbc
+	return res
787cbc
 }
787cbc
 
787cbc
 func (k *Key) IssuerSerial() string {
787cbc
-	return C.GoString(k.k.issuer_serial)
787cbc
+	res := C.GoString(k.k.issuer_serial)
787cbc
+	runtime.KeepAlive(k)
787cbc
+	return res
787cbc
 }
787cbc
 
787cbc
 func (k *Key) IssuerName() string {
787cbc
-	return C.GoString(k.k.issuer_name)
787cbc
+	res := C.GoString(k.k.issuer_name)
787cbc
+	runtime.KeepAlive(k)
787cbc
+	return res
787cbc
 }
787cbc
 
787cbc
 func (k *Key) ChainID() string {
787cbc
-	return C.GoString(k.k.chain_id)
787cbc
+	res := C.GoString(k.k.chain_id)
787cbc
+	runtime.KeepAlive(k)
787cbc
+	return res
787cbc
 }
787cbc
 
787cbc
 func (k *Key) OwnerTrust() Validity {
787cbc
-	return Validity(k.k.owner_trust)
787cbc
+	res := Validity(k.k.owner_trust)
787cbc
+	runtime.KeepAlive(k)
787cbc
+	return res
787cbc
 }
787cbc
 
787cbc
 func (k *Key) SubKeys() *SubKey {
787cbc
-	if k.k.subkeys == nil {
787cbc
+	subKeys := k.k.subkeys
787cbc
+	runtime.KeepAlive(k)
787cbc
+	if subKeys == nil {
787cbc
 		return nil
787cbc
 	}
787cbc
-	return &SubKey{k: k.k.subkeys, parent: k}
787cbc
+	return &SubKey{k: subKeys, parent: k} // The parent: k reference ensures subKeys remains valid
787cbc
 }
787cbc
 
787cbc
 func (k *Key) UserIDs() *UserID {
787cbc
-	if k.k.uids == nil {
787cbc
+	uids := k.k.uids
787cbc
+	runtime.KeepAlive(k)
787cbc
+	if uids == nil {
787cbc
 		return nil
787cbc
 	}
787cbc
-	return &UserID{u: k.k.uids, parent: k}
787cbc
+	return &UserID{u: uids, parent: k} // The parent: k reference ensures uids remains valid
787cbc
 }
787cbc
 
787cbc
 func (k *Key) KeyListMode() KeyListMode {
787cbc
-	return KeyListMode(k.k.keylist_mode)
787cbc
+	res := KeyListMode(k.k.keylist_mode)
787cbc
+	runtime.KeepAlive(k)
787cbc
+	return res
787cbc
 }
787cbc
 
787cbc
 type SubKey struct {
787cbc
@@ -737,12 +950,3 @@ func (u *UserID) Comment() string {
787cbc
 func (u *UserID) Email() string {
787cbc
 	return C.GoString(u.u.email)
787cbc
 }
787cbc
-
787cbc
-// This is somewhat of a horrible hack. We need to unset GPG_AGENT_INFO so that gpgme does not pass --use-agent to GPG.
787cbc
-// os.Unsetenv should be enough, but that only calls the underlying C library (which gpgme uses) if cgo is involved
787cbc
-// - and cgo can't be used in tests. So, provide this helper for test initialization.
787cbc
-func unsetenvGPGAgentInfo() {
787cbc
-	v := C.CString("GPG_AGENT_INFO")
787cbc
-	defer C.free(unsafe.Pointer(v))
787cbc
-	C.unsetenv(v)
787cbc
-}
787cbc
diff --git a/vendor/github.com/mtrmac/gpgme/unset_agent_info.go b/vendor/github.com/mtrmac/gpgme/unset_agent_info.go
787cbc
new file mode 100644
787cbc
index 000000000..986aca59f
787cbc
--- /dev/null
787cbc
+++ b/vendor/github.com/mtrmac/gpgme/unset_agent_info.go
787cbc
@@ -0,0 +1,18 @@
787cbc
+// +build !windows
787cbc
+
787cbc
+package gpgme
787cbc
+
787cbc
+// #include <stdlib.h>
787cbc
+import "C"
787cbc
+import (
787cbc
+	"unsafe"
787cbc
+)
787cbc
+
787cbc
+// This is somewhat of a horrible hack. We need to unset GPG_AGENT_INFO so that gpgme does not pass --use-agent to GPG.
787cbc
+// os.Unsetenv should be enough, but that only calls the underlying C library (which gpgme uses) if cgo is involved
787cbc
+// - and cgo can't be used in tests. So, provide this helper for test initialization.
787cbc
+func unsetenvGPGAgentInfo() {
787cbc
+	v := C.CString("GPG_AGENT_INFO")
787cbc
+	defer C.free(unsafe.Pointer(v))
787cbc
+	C.unsetenv(v)
787cbc
+}
787cbc
diff --git a/vendor/github.com/mtrmac/gpgme/unset_agent_info_windows.go b/vendor/github.com/mtrmac/gpgme/unset_agent_info_windows.go
787cbc
new file mode 100644
787cbc
index 000000000..431ec86d3
787cbc
--- /dev/null
787cbc
+++ b/vendor/github.com/mtrmac/gpgme/unset_agent_info_windows.go
787cbc
@@ -0,0 +1,14 @@
787cbc
+package gpgme
787cbc
+
787cbc
+// #include <stdlib.h>
787cbc
+import "C"
787cbc
+import (
787cbc
+	"unsafe"
787cbc
+)
787cbc
+
787cbc
+// unsetenv is not available in mingw
787cbc
+func unsetenvGPGAgentInfo() {
787cbc
+	v := C.CString("GPG_AGENT_INFO=")
787cbc
+	defer C.free(unsafe.Pointer(v))
787cbc
+	C.putenv(v)
787cbc
+}
787cbc
diff --git a/vendor/modules.txt b/vendor/modules.txt
787cbc
index 013f7f5ec..6cb286331 100644
787cbc
--- a/vendor/modules.txt
787cbc
+++ b/vendor/modules.txt
787cbc
@@ -189,7 +189,7 @@ github.com/mattn/go-isatty
787cbc
 github.com/mattn/go-shellwords
787cbc
 # github.com/mistifyio/go-zfs v2.1.1+incompatible
787cbc
 github.com/mistifyio/go-zfs
787cbc
-# github.com/mtrmac/gpgme v0.0.0-20170102180018-b2432428689c
787cbc
+# github.com/mtrmac/gpgme v0.1.2
787cbc
 github.com/mtrmac/gpgme
787cbc
 # github.com/opencontainers/go-digest v1.0.0-rc1
787cbc
 github.com/opencontainers/go-digest
787cbc
787cbc
From 41a8eabf72768a2d55d819bf78ede96b7a7854e0 Mon Sep 17 00:00:00 2001
787cbc
From: Giuseppe Scrivano <gscrivan@redhat.com>
787cbc
Date: Wed, 30 Oct 2019 08:12:48 +0100
787cbc
Subject: [PATCH 2/3] Dockerfile: use golang-github-cpuguy83-go-md2man
787cbc
787cbc
the package was renamed on Fedora 31.
787cbc
787cbc
Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
787cbc
---
787cbc
 Dockerfile | 2 +-
787cbc
 1 file changed, 1 insertion(+), 1 deletion(-)
787cbc
787cbc
diff --git a/Dockerfile b/Dockerfile
787cbc
index 80b5fd62c..a62cdf106 100644
787cbc
--- a/Dockerfile
787cbc
+++ b/Dockerfile
787cbc
@@ -1,6 +1,6 @@
787cbc
 FROM fedora
787cbc
 
787cbc
-RUN dnf -y update && dnf install -y make git golang golang-github-cpuguy83-go-md2man \
787cbc
+RUN dnf -y update && dnf install -y make git golang golang-github-cpuguy83-md2man \
787cbc
 	# storage deps
787cbc
 	btrfs-progs-devel \
787cbc
 	device-mapper-devel \
787cbc
787cbc
From 27a8cd845d71acb041e4a0219c4f998576211034 Mon Sep 17 00:00:00 2001
787cbc
From: =?UTF-8?q?Miloslav=20Trma=C4=8D?= <mitr@redhat.com>
787cbc
Date: Thu, 31 Oct 2019 17:33:35 +0100
787cbc
Subject: [PATCH 3/3] Revert "Temporarily work around auth.json location
787cbc
 confusion"
787cbc
MIME-Version: 1.0
787cbc
Content-Type: text/plain; charset=UTF-8
787cbc
Content-Transfer-Encoding: 8bit
787cbc
787cbc
This reverts commit 4962559e5cb79a0d6d869b1c26dbc0171354eb73.
787cbc
787cbc
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
787cbc
---
787cbc
 systemtest/040-local-registry-auth.bats | 9 ---------
787cbc
 1 file changed, 9 deletions(-)
787cbc
787cbc
diff --git a/systemtest/040-local-registry-auth.bats b/systemtest/040-local-registry-auth.bats
787cbc
index 2705d0d55..fe1b2f974 100644
787cbc
--- a/systemtest/040-local-registry-auth.bats
787cbc
+++ b/systemtest/040-local-registry-auth.bats
787cbc
@@ -14,15 +14,6 @@ function setup() {
787cbc
     mkdir -p $_cred_dir/containers
787cbc
     rm -f $_cred_dir/containers/auth.json
787cbc
 
787cbc
-    # TODO: This is here to work around
787cbc
-    # https://github.com/containers/libpod/issues/4227 in the
787cbc
-    # "auth: credentials via podman login" test.
787cbc
-    # It should be removed once a packaged version of podman which includes
787cbc
-    # that fix is available in our CI environment, since we _want_ to be
787cbc
-    # checking that podman and skopeo agree on the default for where registry
787cbc
-    # credentials should be stored.
787cbc
-    export REGISTRY_AUTH_FILE=$_cred_dir/containers/auth.json
787cbc
-
787cbc
     # Start authenticated registry with random password
787cbc
     testuser=testuser
787cbc
     testpassword=$(random_string 15)