Blame SOURCES/docker-CVE-2020-8945.patch

a7f575
From 31b404f4a08322a5cf06b1d0637a4ada4323cbb1 Mon Sep 17 00:00:00 2001
a7f575
From: =?UTF-8?q?Miloslav=20Trma=C4=8D?= <mitr@redhat.com>
a7f575
Date: Thu, 20 Feb 2020 16:30:08 +0100
a7f575
Subject: [PATCH 1/2] Remove vendor/src/github.com/mtrmac/gpgme/
a7f575
MIME-Version: 1.0
a7f575
Content-Type: text/plain; charset=UTF-8
a7f575
Content-Transfer-Encoding: 8bit
a7f575
a7f575
This seems to be a mistaken commit of an intermediate build state
a7f575
in the old times when vendoring was used via a GOPATH at vendor/src/...
a7f575
a7f575
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
a7f575
---
a7f575
 vendor/src/github.com/mtrmac/gpgme/LICENSE    |  12 -
a7f575
 .../src/github.com/mtrmac/gpgme/callbacks.go  |  42 -
a7f575
 vendor/src/github.com/mtrmac/gpgme/data.go    | 191 -----
a7f575
 vendor/src/github.com/mtrmac/gpgme/go_gpgme.c |  89 ---
a7f575
 vendor/src/github.com/mtrmac/gpgme/go_gpgme.h |  37 -
a7f575
 vendor/src/github.com/mtrmac/gpgme/gpgme.go   | 740 ------------------
a7f575
 6 files changed, 1111 deletions(-)
a7f575
 delete mode 100644 vendor/src/github.com/mtrmac/gpgme/LICENSE
a7f575
 delete mode 100644 vendor/src/github.com/mtrmac/gpgme/callbacks.go
a7f575
 delete mode 100644 vendor/src/github.com/mtrmac/gpgme/data.go
a7f575
 delete mode 100644 vendor/src/github.com/mtrmac/gpgme/go_gpgme.c
a7f575
 delete mode 100644 vendor/src/github.com/mtrmac/gpgme/go_gpgme.h
a7f575
 delete mode 100644 vendor/src/github.com/mtrmac/gpgme/gpgme.go
a7f575
a7f575
diff --git a/vendor/src/github.com/mtrmac/gpgme/LICENSE b/vendor/src/github.com/mtrmac/gpgme/LICENSE
a7f575
deleted file mode 100644
a7f575
index 06d4ab77316f..000000000000
a7f575
--- a/vendor/src/github.com/mtrmac/gpgme/LICENSE
a7f575
+++ /dev/null
a7f575
@@ -1,12 +0,0 @@
a7f575
-Copyright (c) 2015, James Fargher <proglottis@gmail.com>
a7f575
-All rights reserved.
a7f575
-
a7f575
-Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
a7f575
-
a7f575
-1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
a7f575
-
a7f575
-2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
a7f575
-
a7f575
-3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
a7f575
-
a7f575
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
a7f575
diff --git a/vendor/src/github.com/mtrmac/gpgme/callbacks.go b/vendor/src/github.com/mtrmac/gpgme/callbacks.go
a7f575
deleted file mode 100644
a7f575
index d1dc610d42a8..000000000000
a7f575
--- a/vendor/src/github.com/mtrmac/gpgme/callbacks.go
a7f575
+++ /dev/null
a7f575
@@ -1,42 +0,0 @@
a7f575
-package gpgme
a7f575
-
a7f575
-import (
a7f575
-	"sync"
a7f575
-)
a7f575
-
a7f575
-var callbacks struct {
a7f575
-	sync.Mutex
a7f575
-	m map[uintptr]interface{}
a7f575
-	c uintptr
a7f575
-}
a7f575
-
a7f575
-func callbackAdd(v interface{}) uintptr {
a7f575
-	callbacks.Lock()
a7f575
-	defer callbacks.Unlock()
a7f575
-	if callbacks.m == nil {
a7f575
-		callbacks.m = make(map[uintptr]interface{})
a7f575
-	}
a7f575
-	callbacks.c++
a7f575
-	ret := callbacks.c
a7f575
-	callbacks.m[ret] = v
a7f575
-	return ret
a7f575
-}
a7f575
-
a7f575
-func callbackLookup(c uintptr) interface{} {
a7f575
-	callbacks.Lock()
a7f575
-	defer callbacks.Unlock()
a7f575
-	ret := callbacks.m[c]
a7f575
-	if ret == nil {
a7f575
-		panic("callback pointer not found")
a7f575
-	}
a7f575
-	return ret
a7f575
-}
a7f575
-
a7f575
-func callbackDelete(c uintptr) {
a7f575
-	callbacks.Lock()
a7f575
-	defer callbacks.Unlock()
a7f575
-	if callbacks.m[c] == nil {
a7f575
-		panic("callback pointer not found")
a7f575
-	}
a7f575
-	delete(callbacks.m, c)
a7f575
-}
a7f575
diff --git a/vendor/src/github.com/mtrmac/gpgme/data.go b/vendor/src/github.com/mtrmac/gpgme/data.go
a7f575
deleted file mode 100644
a7f575
index eebc9726347d..000000000000
a7f575
--- a/vendor/src/github.com/mtrmac/gpgme/data.go
a7f575
+++ /dev/null
a7f575
@@ -1,191 +0,0 @@
a7f575
-package gpgme
a7f575
-
a7f575
-// #include <string.h>
a7f575
-// #include <gpgme.h>
a7f575
-// #include <errno.h>
a7f575
-// #include "go_gpgme.h"
a7f575
-import "C"
a7f575
-
a7f575
-import (
a7f575
-	"io"
a7f575
-	"os"
a7f575
-	"runtime"
a7f575
-	"unsafe"
a7f575
-)
a7f575
-
a7f575
-const (
a7f575
-	SeekSet = C.SEEK_SET
a7f575
-	SeekCur = C.SEEK_CUR
a7f575
-	SeekEnd = C.SEEK_END
a7f575
-)
a7f575
-
a7f575
-//export gogpgme_readfunc
a7f575
-func gogpgme_readfunc(handle, buffer unsafe.Pointer, size C.size_t) C.ssize_t {
a7f575
-	d := callbackLookup(uintptr(handle)).(*Data)
a7f575
-	if len(d.buf) < int(size) {
a7f575
-		d.buf = make([]byte, size)
a7f575
-	}
a7f575
-	n, err := d.r.Read(d.buf[:size])
a7f575
-	if err != nil && err != io.EOF {
a7f575
-		C.gpgme_err_set_errno(C.EIO)
a7f575
-		return -1
a7f575
-	}
a7f575
-	C.memcpy(buffer, unsafe.Pointer(&d.buf[0]), C.size_t(n))
a7f575
-	return C.ssize_t(n)
a7f575
-}
a7f575
-
a7f575
-//export gogpgme_writefunc
a7f575
-func gogpgme_writefunc(handle, buffer unsafe.Pointer, size C.size_t) C.ssize_t {
a7f575
-	d := callbackLookup(uintptr(handle)).(*Data)
a7f575
-	if len(d.buf) < int(size) {
a7f575
-		d.buf = make([]byte, size)
a7f575
-	}
a7f575
-	C.memcpy(unsafe.Pointer(&d.buf[0]), buffer, C.size_t(size))
a7f575
-	n, err := d.w.Write(d.buf[:size])
a7f575
-	if err != nil && err != io.EOF {
a7f575
-		C.gpgme_err_set_errno(C.EIO)
a7f575
-		return -1
a7f575
-	}
a7f575
-	return C.ssize_t(n)
a7f575
-}
a7f575
-
a7f575
-//export gogpgme_seekfunc
a7f575
-func gogpgme_seekfunc(handle unsafe.Pointer, offset C.off_t, whence C.int) C.off_t {
a7f575
-	d := callbackLookup(uintptr(handle)).(*Data)
a7f575
-	n, err := d.s.Seek(int64(offset), int(whence))
a7f575
-	if err != nil {
a7f575
-		C.gpgme_err_set_errno(C.EIO)
a7f575
-		return -1
a7f575
-	}
a7f575
-	return C.off_t(n)
a7f575
-}
a7f575
-
a7f575
-// The Data buffer used to communicate with GPGME
a7f575
-type Data struct {
a7f575
-	dh  C.gpgme_data_t
a7f575
-	buf []byte
a7f575
-	cbs C.struct_gpgme_data_cbs
a7f575
-	r   io.Reader
a7f575
-	w   io.Writer
a7f575
-	s   io.Seeker
a7f575
-	cbc uintptr
a7f575
-}
a7f575
-
a7f575
-func newData() *Data {
a7f575
-	d := &Data{}
a7f575
-	runtime.SetFinalizer(d, (*Data).Close)
a7f575
-	return d
a7f575
-}
a7f575
-
a7f575
-// NewData returns a new memory based data buffer
a7f575
-func NewData() (*Data, error) {
a7f575
-	d := newData()
a7f575
-	return d, handleError(C.gpgme_data_new(&d.dh))
a7f575
-}
a7f575
-
a7f575
-// NewDataFile returns a new file based data buffer
a7f575
-func NewDataFile(f *os.File) (*Data, error) {
a7f575
-	d := newData()
a7f575
-	return d, handleError(C.gpgme_data_new_from_fd(&d.dh, C.int(f.Fd())))
a7f575
-}
a7f575
-
a7f575
-// NewDataBytes returns a new memory based data buffer that contains `b` bytes
a7f575
-func NewDataBytes(b []byte) (*Data, error) {
a7f575
-	d := newData()
a7f575
-	var cb *C.char
a7f575
-	if len(b) != 0 {
a7f575
-		cb = (*C.char)(unsafe.Pointer(&b[0]))
a7f575
-	}
a7f575
-	return d, handleError(C.gpgme_data_new_from_mem(&d.dh, cb, C.size_t(len(b)), 1))
a7f575
-}
a7f575
-
a7f575
-// NewDataReader returns a new callback based data buffer
a7f575
-func NewDataReader(r io.Reader) (*Data, error) {
a7f575
-	d := newData()
a7f575
-	d.r = r
a7f575
-	d.cbs.read = C.gpgme_data_read_cb_t(C.gogpgme_readfunc)
a7f575
-	cbc := callbackAdd(d)
a7f575
-	d.cbc = cbc
a7f575
-	return d, handleError(C.gogpgme_data_new_from_cbs(&d.dh, &d.cbs, C.uintptr_t(cbc)))
a7f575
-}
a7f575
-
a7f575
-// NewDataWriter returns a new callback based data buffer
a7f575
-func NewDataWriter(w io.Writer) (*Data, error) {
a7f575
-	d := newData()
a7f575
-	d.w = w
a7f575
-	d.cbs.write = C.gpgme_data_write_cb_t(C.gogpgme_writefunc)
a7f575
-	cbc := callbackAdd(d)
a7f575
-	d.cbc = cbc
a7f575
-	return d, handleError(C.gogpgme_data_new_from_cbs(&d.dh, &d.cbs, C.uintptr_t(cbc)))
a7f575
-}
a7f575
-
a7f575
-// NewDataReadWriter returns a new callback based data buffer
a7f575
-func NewDataReadWriter(rw io.ReadWriter) (*Data, error) {
a7f575
-	d := newData()
a7f575
-	d.r = rw
a7f575
-	d.w = rw
a7f575
-	d.cbs.read = C.gpgme_data_read_cb_t(C.gogpgme_readfunc)
a7f575
-	d.cbs.write = C.gpgme_data_write_cb_t(C.gogpgme_writefunc)
a7f575
-	cbc := callbackAdd(d)
a7f575
-	d.cbc = cbc
a7f575
-	return d, handleError(C.gogpgme_data_new_from_cbs(&d.dh, &d.cbs, C.uintptr_t(cbc)))
a7f575
-}
a7f575
-
a7f575
-// NewDataReadWriteSeeker returns a new callback based data buffer
a7f575
-func NewDataReadWriteSeeker(rw io.ReadWriteSeeker) (*Data, error) {
a7f575
-	d := newData()
a7f575
-	d.r = rw
a7f575
-	d.w = rw
a7f575
-	d.s = rw
a7f575
-	d.cbs.read = C.gpgme_data_read_cb_t(C.gogpgme_readfunc)
a7f575
-	d.cbs.write = C.gpgme_data_write_cb_t(C.gogpgme_writefunc)
a7f575
-	d.cbs.seek = C.gpgme_data_seek_cb_t(C.gogpgme_seekfunc)
a7f575
-	cbc := callbackAdd(d)
a7f575
-	d.cbc = cbc
a7f575
-	return d, handleError(C.gogpgme_data_new_from_cbs(&d.dh, &d.cbs, C.uintptr_t(cbc)))
a7f575
-}
a7f575
-
a7f575
-// Close releases any resources associated with the data buffer
a7f575
-func (d *Data) Close() error {
a7f575
-	if d.dh == nil {
a7f575
-		return nil
a7f575
-	}
a7f575
-	if d.cbc > 0 {
a7f575
-		callbackDelete(d.cbc)
a7f575
-	}
a7f575
-	_, err := C.gpgme_data_release(d.dh)
a7f575
-	d.dh = nil
a7f575
-	return err
a7f575
-}
a7f575
-
a7f575
-func (d *Data) Write(p []byte) (int, error) {
a7f575
-	n, err := C.gpgme_data_write(d.dh, unsafe.Pointer(&p[0]), C.size_t(len(p)))
a7f575
-	if err != nil {
a7f575
-		return 0, err
a7f575
-	}
a7f575
-	if n == 0 {
a7f575
-		return 0, io.EOF
a7f575
-	}
a7f575
-	return int(n), nil
a7f575
-}
a7f575
-
a7f575
-func (d *Data) Read(p []byte) (int, error) {
a7f575
-	n, err := C.gpgme_data_read(d.dh, unsafe.Pointer(&p[0]), C.size_t(len(p)))
a7f575
-	if err != nil {
a7f575
-		return 0, err
a7f575
-	}
a7f575
-	if n == 0 {
a7f575
-		return 0, io.EOF
a7f575
-	}
a7f575
-	return int(n), nil
a7f575
-}
a7f575
-
a7f575
-func (d *Data) Seek(offset int64, whence int) (int64, error) {
a7f575
-	n, err := C.gpgme_data_seek(d.dh, C.off_t(offset), C.int(whence))
a7f575
-	return int64(n), err
a7f575
-}
a7f575
-
a7f575
-// Name returns the associated filename if any
a7f575
-func (d *Data) Name() string {
a7f575
-	return C.GoString(C.gpgme_data_get_file_name(d.dh))
a7f575
-}
a7f575
diff --git a/vendor/src/github.com/mtrmac/gpgme/go_gpgme.c b/vendor/src/github.com/mtrmac/gpgme/go_gpgme.c
a7f575
deleted file mode 100644
a7f575
index b887574e0cb9..000000000000
a7f575
--- a/vendor/src/github.com/mtrmac/gpgme/go_gpgme.c
a7f575
+++ /dev/null
a7f575
@@ -1,89 +0,0 @@
a7f575
-#include "go_gpgme.h"
a7f575
-
a7f575
-gpgme_error_t gogpgme_data_new_from_cbs(gpgme_data_t *dh, gpgme_data_cbs_t cbs, uintptr_t handle) {
a7f575
-	return gpgme_data_new_from_cbs(dh, cbs, (void *)handle);
a7f575
-}
a7f575
-
a7f575
-void gogpgme_set_passphrase_cb(gpgme_ctx_t ctx, gpgme_passphrase_cb_t cb, uintptr_t handle) {
a7f575
-	gpgme_set_passphrase_cb(ctx, cb, (void *)handle);
a7f575
-}
a7f575
-
a7f575
-unsigned int key_revoked(gpgme_key_t k) {
a7f575
-	return k->revoked;
a7f575
-}
a7f575
-
a7f575
-unsigned int key_expired(gpgme_key_t k) {
a7f575
-	return k->expired;
a7f575
-}
a7f575
-
a7f575
-unsigned int key_disabled(gpgme_key_t k) {
a7f575
-	return k->disabled;
a7f575
-}
a7f575
-
a7f575
-unsigned int key_invalid(gpgme_key_t k) {
a7f575
-	return k->invalid;
a7f575
-}
a7f575
-
a7f575
-unsigned int key_can_encrypt(gpgme_key_t k) {
a7f575
-	return k->can_encrypt;
a7f575
-}
a7f575
-
a7f575
-unsigned int key_can_sign(gpgme_key_t k) {
a7f575
-	return k->can_sign;
a7f575
-}
a7f575
-
a7f575
-unsigned int key_can_certify(gpgme_key_t k) {
a7f575
-	return k->can_certify;
a7f575
-}
a7f575
-
a7f575
-unsigned int key_secret(gpgme_key_t k) {
a7f575
-	return k->secret;
a7f575
-}
a7f575
-
a7f575
-unsigned int key_can_authenticate(gpgme_key_t k) {
a7f575
-	return k->can_authenticate;
a7f575
-}
a7f575
-
a7f575
-unsigned int key_is_qualified(gpgme_key_t k) {
a7f575
-	return k->is_qualified;
a7f575
-}
a7f575
-
a7f575
-unsigned int signature_wrong_key_usage(gpgme_signature_t s) {
a7f575
-    return s->wrong_key_usage;
a7f575
-}
a7f575
-
a7f575
-unsigned int signature_pka_trust(gpgme_signature_t s) {
a7f575
-    return s->pka_trust;
a7f575
-}
a7f575
-
a7f575
-unsigned int signature_chain_model(gpgme_signature_t s) {
a7f575
-    return s->chain_model;
a7f575
-}
a7f575
-
a7f575
-unsigned int subkey_revoked(gpgme_subkey_t k) {
a7f575
-	return k->revoked;
a7f575
-}
a7f575
-
a7f575
-unsigned int subkey_expired(gpgme_subkey_t k) {
a7f575
-	return k->expired;
a7f575
-}
a7f575
-
a7f575
-unsigned int subkey_disabled(gpgme_subkey_t k) {
a7f575
-	return k->disabled;
a7f575
-}
a7f575
-
a7f575
-unsigned int subkey_invalid(gpgme_subkey_t k) {
a7f575
-	return k->invalid;
a7f575
-}
a7f575
-
a7f575
-unsigned int subkey_secret(gpgme_subkey_t k) {
a7f575
-	return k->secret;
a7f575
-}
a7f575
-
a7f575
-unsigned int uid_revoked(gpgme_user_id_t u) {
a7f575
-	return u->revoked;
a7f575
-}
a7f575
-
a7f575
-unsigned int uid_invalid(gpgme_user_id_t u) {
a7f575
-	return u->invalid;
a7f575
-}
a7f575
diff --git a/vendor/src/github.com/mtrmac/gpgme/go_gpgme.h b/vendor/src/github.com/mtrmac/gpgme/go_gpgme.h
a7f575
deleted file mode 100644
a7f575
index a3678b127ac7..000000000000
a7f575
--- a/vendor/src/github.com/mtrmac/gpgme/go_gpgme.h
a7f575
+++ /dev/null
a7f575
@@ -1,37 +0,0 @@
a7f575
-#ifndef GO_GPGME_H
a7f575
-#define GO_GPGME_H
a7f575
-
a7f575
-#define _FILE_OFFSET_BITS 64
a7f575
-#include <stdint.h>
a7f575
-
a7f575
-#include <gpgme.h>
a7f575
-
a7f575
-extern ssize_t gogpgme_readfunc(void *handle, void *buffer, size_t size);
a7f575
-extern ssize_t gogpgme_writefunc(void *handle, void *buffer, size_t size);
a7f575
-extern off_t gogpgme_seekfunc(void *handle, off_t offset, int whence);
a7f575
-extern gpgme_error_t gogpgme_passfunc(void *hook, char *uid_hint, char *passphrase_info, int prev_was_bad, int fd);
a7f575
-extern gpgme_error_t gogpgme_data_new_from_cbs(gpgme_data_t *dh, gpgme_data_cbs_t cbs, uintptr_t handle);
a7f575
-extern void gogpgme_set_passphrase_cb(gpgme_ctx_t ctx, gpgme_passphrase_cb_t cb, uintptr_t handle);
a7f575
-
a7f575
-extern unsigned int key_revoked(gpgme_key_t k);
a7f575
-extern unsigned int key_expired(gpgme_key_t k);
a7f575
-extern unsigned int key_disabled(gpgme_key_t k);
a7f575
-extern unsigned int key_invalid(gpgme_key_t k);
a7f575
-extern unsigned int key_can_encrypt(gpgme_key_t k);
a7f575
-extern unsigned int key_can_sign(gpgme_key_t k);
a7f575
-extern unsigned int key_can_certify(gpgme_key_t k);
a7f575
-extern unsigned int key_secret(gpgme_key_t k);
a7f575
-extern unsigned int key_can_authenticate(gpgme_key_t k);
a7f575
-extern unsigned int key_is_qualified(gpgme_key_t k);
a7f575
-extern unsigned int signature_wrong_key_usage(gpgme_signature_t s);
a7f575
-extern unsigned int signature_pka_trust(gpgme_signature_t s);
a7f575
-extern unsigned int signature_chain_model(gpgme_signature_t s);
a7f575
-extern unsigned int subkey_revoked(gpgme_subkey_t k);
a7f575
-extern unsigned int subkey_expired(gpgme_subkey_t k);
a7f575
-extern unsigned int subkey_disabled(gpgme_subkey_t k);
a7f575
-extern unsigned int subkey_invalid(gpgme_subkey_t k);
a7f575
-extern unsigned int subkey_secret(gpgme_subkey_t k);
a7f575
-extern unsigned int uid_revoked(gpgme_user_id_t u);
a7f575
-extern unsigned int uid_invalid(gpgme_user_id_t u);
a7f575
-
a7f575
-#endif
a7f575
diff --git a/vendor/src/github.com/mtrmac/gpgme/gpgme.go b/vendor/src/github.com/mtrmac/gpgme/gpgme.go
a7f575
deleted file mode 100644
a7f575
index 5f1793eab32d..000000000000
a7f575
--- a/vendor/src/github.com/mtrmac/gpgme/gpgme.go
a7f575
+++ /dev/null
a7f575
@@ -1,740 +0,0 @@
a7f575
-// Package gpgme provides a Go wrapper for the GPGME library
a7f575
-package gpgme
a7f575
-
a7f575
-// #cgo LDFLAGS: -lgpgme -lassuan -lgpg-error
a7f575
-// #cgo CPPFLAGS: -D_FILE_OFFSET_BITS=64
a7f575
-// #include <stdlib.h>
a7f575
-// #include <gpgme.h>
a7f575
-// #include "go_gpgme.h"
a7f575
-import "C"
a7f575
-
a7f575
-import (
a7f575
-	"io"
a7f575
-	"os"
a7f575
-	"runtime"
a7f575
-	"time"
a7f575
-	"unsafe"
a7f575
-)
a7f575
-
a7f575
-var Version string
a7f575
-
a7f575
-func init() {
a7f575
-	Version = C.GoString(C.gpgme_check_version(nil))
a7f575
-}
a7f575
-
a7f575
-// Callback is the function that is called when a passphrase is required
a7f575
-type Callback func(uidHint string, prevWasBad bool, f *os.File) error
a7f575
-
a7f575
-//export gogpgme_passfunc
a7f575
-func gogpgme_passfunc(hook unsafe.Pointer, uid_hint, passphrase_info *C.char, prev_was_bad, fd C.int) C.gpgme_error_t {
a7f575
-	c := callbackLookup(uintptr(hook)).(*Context)
a7f575
-	go_uid_hint := C.GoString(uid_hint)
a7f575
-	f := os.NewFile(uintptr(fd), go_uid_hint)
a7f575
-	defer f.Close()
a7f575
-	err := c.callback(go_uid_hint, prev_was_bad != 0, f)
a7f575
-	if err != nil {
a7f575
-		return C.GPG_ERR_CANCELED
a7f575
-	}
a7f575
-	return 0
a7f575
-}
a7f575
-
a7f575
-type Protocol int
a7f575
-
a7f575
-const (
a7f575
-	ProtocolOpenPGP  Protocol = C.GPGME_PROTOCOL_OpenPGP
a7f575
-	ProtocolCMS      Protocol = C.GPGME_PROTOCOL_CMS
a7f575
-	ProtocolGPGConf  Protocol = C.GPGME_PROTOCOL_GPGCONF
a7f575
-	ProtocolAssuan   Protocol = C.GPGME_PROTOCOL_ASSUAN
a7f575
-	ProtocolG13      Protocol = C.GPGME_PROTOCOL_G13
a7f575
-	ProtocolUIServer Protocol = C.GPGME_PROTOCOL_UISERVER
a7f575
-	// ProtocolSpawn    Protocol = C.GPGME_PROTOCOL_SPAWN // Unavailable in 1.4.3
a7f575
-	ProtocolDefault Protocol = C.GPGME_PROTOCOL_DEFAULT
a7f575
-	ProtocolUnknown Protocol = C.GPGME_PROTOCOL_UNKNOWN
a7f575
-)
a7f575
-
a7f575
-type PinEntryMode int
a7f575
-
a7f575
-// const ( // Unavailable in 1.3.2
a7f575
-// 	PinEntryDefault  PinEntryMode = C.GPGME_PINENTRY_MODE_DEFAULT
a7f575
-// 	PinEntryAsk      PinEntryMode = C.GPGME_PINENTRY_MODE_ASK
a7f575
-// 	PinEntryCancel   PinEntryMode = C.GPGME_PINENTRY_MODE_CANCEL
a7f575
-// 	PinEntryError    PinEntryMode = C.GPGME_PINENTRY_MODE_ERROR
a7f575
-// 	PinEntryLoopback PinEntryMode = C.GPGME_PINENTRY_MODE_LOOPBACK
a7f575
-// )
a7f575
-
a7f575
-type EncryptFlag uint
a7f575
-
a7f575
-const (
a7f575
-	EncryptAlwaysTrust EncryptFlag = C.GPGME_ENCRYPT_ALWAYS_TRUST
a7f575
-	EncryptNoEncryptTo EncryptFlag = C.GPGME_ENCRYPT_NO_ENCRYPT_TO
a7f575
-	EncryptPrepare     EncryptFlag = C.GPGME_ENCRYPT_PREPARE
a7f575
-	EncryptExceptSign  EncryptFlag = C.GPGME_ENCRYPT_EXPECT_SIGN
a7f575
-	// EncryptNoCompress  EncryptFlag = C.GPGME_ENCRYPT_NO_COMPRESS // Unavailable in 1.4.3
a7f575
-)
a7f575
-
a7f575
-type HashAlgo int
a7f575
-
a7f575
-// const values for HashAlgo values should be added when necessary.
a7f575
-
a7f575
-type KeyListMode uint
a7f575
-
a7f575
-const (
a7f575
-	KeyListModeLocal        KeyListMode = C.GPGME_KEYLIST_MODE_LOCAL
a7f575
-	KeyListModeExtern       KeyListMode = C.GPGME_KEYLIST_MODE_EXTERN
a7f575
-	KeyListModeSigs         KeyListMode = C.GPGME_KEYLIST_MODE_SIGS
a7f575
-	KeyListModeSigNotations KeyListMode = C.GPGME_KEYLIST_MODE_SIG_NOTATIONS
a7f575
-	// KeyListModeWithSecret   KeyListMode = C.GPGME_KEYLIST_MODE_WITH_SECRET // Unavailable in 1.4.3
a7f575
-	KeyListModeEphemeral    KeyListMode = C.GPGME_KEYLIST_MODE_EPHEMERAL
a7f575
-	KeyListModeModeValidate KeyListMode = C.GPGME_KEYLIST_MODE_VALIDATE
a7f575
-)
a7f575
-
a7f575
-type PubkeyAlgo int
a7f575
-
a7f575
-// const values for PubkeyAlgo values should be added when necessary.
a7f575
-
a7f575
-type SigMode int
a7f575
-
a7f575
-const (
a7f575
-	SigModeNormal SigMode = C.GPGME_SIG_MODE_NORMAL
a7f575
-	SigModeDetach SigMode = C.GPGME_SIG_MODE_DETACH
a7f575
-	SigModeClear  SigMode = C.GPGME_SIG_MODE_CLEAR
a7f575
-)
a7f575
-
a7f575
-type SigSum int
a7f575
-
a7f575
-const (
a7f575
-	SigSumValid      SigSum = C.GPGME_SIGSUM_VALID
a7f575
-	SigSumGreen      SigSum = C.GPGME_SIGSUM_GREEN
a7f575
-	SigSumRed        SigSum = C.GPGME_SIGSUM_RED
a7f575
-	SigSumKeyRevoked SigSum = C.GPGME_SIGSUM_KEY_REVOKED
a7f575
-	SigSumKeyExpired SigSum = C.GPGME_SIGSUM_KEY_EXPIRED
a7f575
-	SigSumSigExpired SigSum = C.GPGME_SIGSUM_SIG_EXPIRED
a7f575
-	SigSumKeyMissing SigSum = C.GPGME_SIGSUM_KEY_MISSING
a7f575
-	SigSumCRLMissing SigSum = C.GPGME_SIGSUM_CRL_MISSING
a7f575
-	SigSumCRLTooOld  SigSum = C.GPGME_SIGSUM_CRL_TOO_OLD
a7f575
-	SigSumBadPolicy  SigSum = C.GPGME_SIGSUM_BAD_POLICY
a7f575
-	SigSumSysError   SigSum = C.GPGME_SIGSUM_SYS_ERROR
a7f575
-)
a7f575
-
a7f575
-type Validity int
a7f575
-
a7f575
-const (
a7f575
-	ValidityUnknown   Validity = C.GPGME_VALIDITY_UNKNOWN
a7f575
-	ValidityUndefined Validity = C.GPGME_VALIDITY_UNDEFINED
a7f575
-	ValidityNever     Validity = C.GPGME_VALIDITY_NEVER
a7f575
-	ValidityMarginal  Validity = C.GPGME_VALIDITY_MARGINAL
a7f575
-	ValidityFull      Validity = C.GPGME_VALIDITY_FULL
a7f575
-	ValidityUltimate  Validity = C.GPGME_VALIDITY_ULTIMATE
a7f575
-)
a7f575
-
a7f575
-type ErrorCode int
a7f575
-
a7f575
-const (
a7f575
-	ErrorNoError ErrorCode = C.GPG_ERR_NO_ERROR
a7f575
-	ErrorEOF     ErrorCode = C.GPG_ERR_EOF
a7f575
-)
a7f575
-
a7f575
-// Error is a wrapper for GPGME errors
a7f575
-type Error struct {
a7f575
-	err C.gpgme_error_t
a7f575
-}
a7f575
-
a7f575
-func (e Error) Code() ErrorCode {
a7f575
-	return ErrorCode(C.gpgme_err_code(e.err))
a7f575
-}
a7f575
-
a7f575
-func (e Error) Error() string {
a7f575
-	return C.GoString(C.gpgme_strerror(e.err))
a7f575
-}
a7f575
-
a7f575
-func handleError(err C.gpgme_error_t) error {
a7f575
-	e := Error{err: err}
a7f575
-	if e.Code() == ErrorNoError {
a7f575
-		return nil
a7f575
-	}
a7f575
-	return e
a7f575
-}
a7f575
-
a7f575
-func cbool(b bool) C.int {
a7f575
-	if b {
a7f575
-		return 1
a7f575
-	}
a7f575
-	return 0
a7f575
-}
a7f575
-
a7f575
-func EngineCheckVersion(p Protocol) error {
a7f575
-	return handleError(C.gpgme_engine_check_version(C.gpgme_protocol_t(p)))
a7f575
-}
a7f575
-
a7f575
-type EngineInfo struct {
a7f575
-	info C.gpgme_engine_info_t
a7f575
-}
a7f575
-
a7f575
-func (e *EngineInfo) Next() *EngineInfo {
a7f575
-	if e.info.next == nil {
a7f575
-		return nil
a7f575
-	}
a7f575
-	return &EngineInfo{info: e.info.next}
a7f575
-}
a7f575
-
a7f575
-func (e *EngineInfo) Protocol() Protocol {
a7f575
-	return Protocol(e.info.protocol)
a7f575
-}
a7f575
-
a7f575
-func (e *EngineInfo) FileName() string {
a7f575
-	return C.GoString(e.info.file_name)
a7f575
-}
a7f575
-
a7f575
-func (e *EngineInfo) Version() string {
a7f575
-	return C.GoString(e.info.version)
a7f575
-}
a7f575
-
a7f575
-func (e *EngineInfo) RequiredVersion() string {
a7f575
-	return C.GoString(e.info.req_version)
a7f575
-}
a7f575
-
a7f575
-func (e *EngineInfo) HomeDir() string {
a7f575
-	return C.GoString(e.info.home_dir)
a7f575
-}
a7f575
-
a7f575
-func GetEngineInfo() (*EngineInfo, error) {
a7f575
-	info := &EngineInfo{}
a7f575
-	return info, handleError(C.gpgme_get_engine_info(&info.info))
a7f575
-}
a7f575
-
a7f575
-func SetEngineInfo(proto Protocol, fileName, homeDir string) error {
a7f575
-	var cfn, chome *C.char
a7f575
-	if fileName != "" {
a7f575
-		cfn = C.CString(fileName)
a7f575
-		defer C.free(unsafe.Pointer(cfn))
a7f575
-	}
a7f575
-	if homeDir != "" {
a7f575
-		chome = C.CString(homeDir)
a7f575
-		defer C.free(unsafe.Pointer(chome))
a7f575
-	}
a7f575
-	return handleError(C.gpgme_set_engine_info(C.gpgme_protocol_t(proto), cfn, chome))
a7f575
-}
a7f575
-
a7f575
-func FindKeys(pattern string, secretOnly bool) ([]*Key, error) {
a7f575
-	var keys []*Key
a7f575
-	ctx, err := New()
a7f575
-	if err != nil {
a7f575
-		return keys, err
a7f575
-	}
a7f575
-	defer ctx.Release()
a7f575
-	if err := ctx.KeyListStart(pattern, secretOnly); err != nil {
a7f575
-		return keys, err
a7f575
-	}
a7f575
-	defer ctx.KeyListEnd()
a7f575
-	for ctx.KeyListNext() {
a7f575
-		keys = append(keys, ctx.Key)
a7f575
-	}
a7f575
-	if ctx.KeyError != nil {
a7f575
-		return keys, ctx.KeyError
a7f575
-	}
a7f575
-	return keys, nil
a7f575
-}
a7f575
-
a7f575
-func Decrypt(r io.Reader) (*Data, error) {
a7f575
-	ctx, err := New()
a7f575
-	if err != nil {
a7f575
-		return nil, err
a7f575
-	}
a7f575
-	defer ctx.Release()
a7f575
-	cipher, err := NewDataReader(r)
a7f575
-	if err != nil {
a7f575
-		return nil, err
a7f575
-	}
a7f575
-	defer cipher.Close()
a7f575
-	plain, err := NewData()
a7f575
-	if err != nil {
a7f575
-		return nil, err
a7f575
-	}
a7f575
-	err = ctx.Decrypt(cipher, plain)
a7f575
-	plain.Seek(0, SeekSet)
a7f575
-	return plain, err
a7f575
-}
a7f575
-
a7f575
-type Context struct {
a7f575
-	Key      *Key
a7f575
-	KeyError error
a7f575
-
a7f575
-	callback Callback
a7f575
-	cbc      uintptr
a7f575
-
a7f575
-	ctx C.gpgme_ctx_t
a7f575
-}
a7f575
-
a7f575
-func New() (*Context, error) {
a7f575
-	c := &Context{}
a7f575
-	err := C.gpgme_new(&c.ctx)
a7f575
-	runtime.SetFinalizer(c, (*Context).Release)
a7f575
-	return c, handleError(err)
a7f575
-}
a7f575
-
a7f575
-func (c *Context) Release() {
a7f575
-	if c.ctx == nil {
a7f575
-		return
a7f575
-	}
a7f575
-	if c.cbc > 0 {
a7f575
-		callbackDelete(c.cbc)
a7f575
-	}
a7f575
-	C.gpgme_release(c.ctx)
a7f575
-	c.ctx = nil
a7f575
-}
a7f575
-
a7f575
-func (c *Context) SetArmor(yes bool) {
a7f575
-	C.gpgme_set_armor(c.ctx, cbool(yes))
a7f575
-}
a7f575
-
a7f575
-func (c *Context) Armor() bool {
a7f575
-	return C.gpgme_get_armor(c.ctx) != 0
a7f575
-}
a7f575
-
a7f575
-func (c *Context) SetTextMode(yes bool) {
a7f575
-	C.gpgme_set_textmode(c.ctx, cbool(yes))
a7f575
-}
a7f575
-
a7f575
-func (c *Context) TextMode() bool {
a7f575
-	return C.gpgme_get_textmode(c.ctx) != 0
a7f575
-}
a7f575
-
a7f575
-func (c *Context) SetProtocol(p Protocol) error {
a7f575
-	return handleError(C.gpgme_set_protocol(c.ctx, C.gpgme_protocol_t(p)))
a7f575
-}
a7f575
-
a7f575
-func (c *Context) Protocol() Protocol {
a7f575
-	return Protocol(C.gpgme_get_protocol(c.ctx))
a7f575
-}
a7f575
-
a7f575
-func (c *Context) SetKeyListMode(m KeyListMode) error {
a7f575
-	return handleError(C.gpgme_set_keylist_mode(c.ctx, C.gpgme_keylist_mode_t(m)))
a7f575
-}
a7f575
-
a7f575
-func (c *Context) KeyListMode() KeyListMode {
a7f575
-	return KeyListMode(C.gpgme_get_keylist_mode(c.ctx))
a7f575
-}
a7f575
-
a7f575
-// Unavailable in 1.3.2:
a7f575
-// func (c *Context) SetPinEntryMode(m PinEntryMode) error {
a7f575
-// 	return handleError(C.gpgme_set_pinentry_mode(c.ctx, C.gpgme_pinentry_mode_t(m)))
a7f575
-// }
a7f575
-
a7f575
-// Unavailable in 1.3.2:
a7f575
-// func (c *Context) PinEntryMode() PinEntryMode {
a7f575
-// 	return PinEntryMode(C.gpgme_get_pinentry_mode(c.ctx))
a7f575
-// }
a7f575
-
a7f575
-func (c *Context) SetCallback(callback Callback) error {
a7f575
-	var err error
a7f575
-	c.callback = callback
a7f575
-	if c.cbc > 0 {
a7f575
-		callbackDelete(c.cbc)
a7f575
-	}
a7f575
-	if callback != nil {
a7f575
-		cbc := callbackAdd(c)
a7f575
-		c.cbc = cbc
a7f575
-		_, err = C.gogpgme_set_passphrase_cb(c.ctx, C.gpgme_passphrase_cb_t(C.gogpgme_passfunc), C.uintptr_t(cbc))
a7f575
-	} else {
a7f575
-		c.cbc = 0
a7f575
-		_, err = C.gogpgme_set_passphrase_cb(c.ctx, nil, 0)
a7f575
-	}
a7f575
-	return err
a7f575
-}
a7f575
-
a7f575
-func (c *Context) EngineInfo() *EngineInfo {
a7f575
-	return &EngineInfo{info: C.gpgme_ctx_get_engine_info(c.ctx)}
a7f575
-}
a7f575
-
a7f575
-func (c *Context) SetEngineInfo(proto Protocol, fileName, homeDir string) error {
a7f575
-	var cfn, chome *C.char
a7f575
-	if fileName != "" {
a7f575
-		cfn = C.CString(fileName)
a7f575
-		defer C.free(unsafe.Pointer(cfn))
a7f575
-	}
a7f575
-	if homeDir != "" {
a7f575
-		chome = C.CString(homeDir)
a7f575
-		defer C.free(unsafe.Pointer(chome))
a7f575
-	}
a7f575
-	return handleError(C.gpgme_ctx_set_engine_info(c.ctx, C.gpgme_protocol_t(proto), cfn, chome))
a7f575
-}
a7f575
-
a7f575
-func (c *Context) KeyListStart(pattern string, secretOnly bool) error {
a7f575
-	cpattern := C.CString(pattern)
a7f575
-	defer C.free(unsafe.Pointer(cpattern))
a7f575
-	err := C.gpgme_op_keylist_start(c.ctx, cpattern, cbool(secretOnly))
a7f575
-	return handleError(err)
a7f575
-}
a7f575
-
a7f575
-func (c *Context) KeyListNext() bool {
a7f575
-	c.Key = newKey()
a7f575
-	err := handleError(C.gpgme_op_keylist_next(c.ctx, &c.Key.k))
a7f575
-	if err != nil {
a7f575
-		if e, ok := err.(Error); ok && e.Code() == ErrorEOF {
a7f575
-			c.KeyError = nil
a7f575
-		} else {
a7f575
-			c.KeyError = err
a7f575
-		}
a7f575
-		return false
a7f575
-	}
a7f575
-	c.KeyError = nil
a7f575
-	return true
a7f575
-}
a7f575
-
a7f575
-func (c *Context) KeyListEnd() error {
a7f575
-	return handleError(C.gpgme_op_keylist_end(c.ctx))
a7f575
-}
a7f575
-
a7f575
-func (c *Context) GetKey(fingerprint string, secret bool) (*Key, error) {
a7f575
-	key := newKey()
a7f575
-	cfpr := C.CString(fingerprint)
a7f575
-	defer C.free(unsafe.Pointer(cfpr))
a7f575
-	return key, handleError(C.gpgme_get_key(c.ctx, cfpr, &key.k, cbool(secret)))
a7f575
-}
a7f575
-
a7f575
-func (c *Context) Decrypt(ciphertext, plaintext *Data) error {
a7f575
-	return handleError(C.gpgme_op_decrypt(c.ctx, ciphertext.dh, plaintext.dh))
a7f575
-}
a7f575
-
a7f575
-func (c *Context) DecryptVerify(ciphertext, plaintext *Data) error {
a7f575
-	return handleError(C.gpgme_op_decrypt_verify(c.ctx, ciphertext.dh, plaintext.dh))
a7f575
-}
a7f575
-
a7f575
-type Signature struct {
a7f575
-	Summary        SigSum
a7f575
-	Fingerprint    string
a7f575
-	Status         error
a7f575
-	Timestamp      time.Time
a7f575
-	ExpTimestamp   time.Time
a7f575
-	WrongKeyUsage  bool
a7f575
-	PKATrust       uint
a7f575
-	ChainModel     bool
a7f575
-	Validity       Validity
a7f575
-	ValidityReason error
a7f575
-	PubkeyAlgo     PubkeyAlgo
a7f575
-	HashAlgo       HashAlgo
a7f575
-}
a7f575
-
a7f575
-func (c *Context) Verify(sig, signedText, plain *Data) (string, []Signature, error) {
a7f575
-	var signedTextPtr, plainPtr C.gpgme_data_t = nil, nil
a7f575
-	if signedText != nil {
a7f575
-		signedTextPtr = signedText.dh
a7f575
-	}
a7f575
-	if plain != nil {
a7f575
-		plainPtr = plain.dh
a7f575
-	}
a7f575
-	err := handleError(C.gpgme_op_verify(c.ctx, sig.dh, signedTextPtr, plainPtr))
a7f575
-	if err != nil {
a7f575
-		return "", nil, err
a7f575
-	}
a7f575
-	res := C.gpgme_op_verify_result(c.ctx)
a7f575
-	sigs := []Signature{}
a7f575
-	for s := res.signatures; s != nil; s = s.next {
a7f575
-		sig := Signature{
a7f575
-			Summary:     SigSum(s.summary),
a7f575
-			Fingerprint: C.GoString(s.fpr),
a7f575
-			Status:      handleError(s.status),
a7f575
-			// s.notations not implemented
a7f575
-			Timestamp:      time.Unix(int64(s.timestamp), 0),
a7f575
-			ExpTimestamp:   time.Unix(int64(s.exp_timestamp), 0),
a7f575
-			WrongKeyUsage:  C.signature_wrong_key_usage(s) != 0,
a7f575
-			PKATrust:       uint(C.signature_pka_trust(s)),
a7f575
-			ChainModel:     C.signature_chain_model(s) != 0,
a7f575
-			Validity:       Validity(s.validity),
a7f575
-			ValidityReason: handleError(s.validity_reason),
a7f575
-			PubkeyAlgo:     PubkeyAlgo(s.pubkey_algo),
a7f575
-			HashAlgo:       HashAlgo(s.hash_algo),
a7f575
-		}
a7f575
-		sigs = append(sigs, sig)
a7f575
-	}
a7f575
-	return C.GoString(res.file_name), sigs, nil
a7f575
-}
a7f575
-
a7f575
-func (c *Context) Encrypt(recipients []*Key, flags EncryptFlag, plaintext, ciphertext *Data) error {
a7f575
-	size := unsafe.Sizeof(new(C.gpgme_key_t))
a7f575
-	recp := C.calloc(C.size_t(len(recipients)+1), C.size_t(size))
a7f575
-	defer C.free(recp)
a7f575
-	for i := range recipients {
a7f575
-		ptr := (*C.gpgme_key_t)(unsafe.Pointer(uintptr(recp) + size*uintptr(i)))
a7f575
-		*ptr = recipients[i].k
a7f575
-	}
a7f575
-	err := C.gpgme_op_encrypt(c.ctx, (*C.gpgme_key_t)(recp), C.gpgme_encrypt_flags_t(flags), plaintext.dh, ciphertext.dh)
a7f575
-	return handleError(err)
a7f575
-}
a7f575
-
a7f575
-func (c *Context) Sign(signers []*Key, plain, sig *Data, mode SigMode) error {
a7f575
-	C.gpgme_signers_clear(c.ctx)
a7f575
-	for _, k := range signers {
a7f575
-		if err := handleError(C.gpgme_signers_add(c.ctx, k.k)); err != nil {
a7f575
-			C.gpgme_signers_clear(c.ctx)
a7f575
-			return err
a7f575
-		}
a7f575
-	}
a7f575
-	return handleError(C.gpgme_op_sign(c.ctx, plain.dh, sig.dh, C.gpgme_sig_mode_t(mode)))
a7f575
-}
a7f575
-
a7f575
-// ImportStatusFlags describes the type of ImportStatus.Status. The C API in gpgme.h simply uses "unsigned".
a7f575
-type ImportStatusFlags uint
a7f575
-
a7f575
-const (
a7f575
-	ImportNew    ImportStatusFlags = C.GPGME_IMPORT_NEW
a7f575
-	ImportUID    ImportStatusFlags = C.GPGME_IMPORT_UID
a7f575
-	ImportSIG    ImportStatusFlags = C.GPGME_IMPORT_SIG
a7f575
-	ImportSubKey ImportStatusFlags = C.GPGME_IMPORT_SUBKEY
a7f575
-	ImportSecret ImportStatusFlags = C.GPGME_IMPORT_SECRET
a7f575
-)
a7f575
-
a7f575
-type ImportStatus struct {
a7f575
-	Fingerprint string
a7f575
-	Result      error
a7f575
-	Status      ImportStatusFlags
a7f575
-}
a7f575
-
a7f575
-type ImportResult struct {
a7f575
-	Considered      int
a7f575
-	NoUserID        int
a7f575
-	Imported        int
a7f575
-	ImportedRSA     int
a7f575
-	Unchanged       int
a7f575
-	NewUserIDs      int
a7f575
-	NewSubKeys      int
a7f575
-	NewSignatures   int
a7f575
-	NewRevocations  int
a7f575
-	SecretRead      int
a7f575
-	SecretImported  int
a7f575
-	SecretUnchanged int
a7f575
-	NotImported     int
a7f575
-	Imports         []ImportStatus
a7f575
-}
a7f575
-
a7f575
-func (c *Context) Import(keyData *Data) (*ImportResult, error) {
a7f575
-	err := handleError(C.gpgme_op_import(c.ctx, keyData.dh))
a7f575
-	if err != nil {
a7f575
-		return nil, err
a7f575
-	}
a7f575
-	res := C.gpgme_op_import_result(c.ctx)
a7f575
-	imports := []ImportStatus{}
a7f575
-	for s := res.imports; s != nil; s = s.next {
a7f575
-		imports = append(imports, ImportStatus{
a7f575
-			Fingerprint: C.GoString(s.fpr),
a7f575
-			Result:      handleError(s.result),
a7f575
-			Status:      ImportStatusFlags(s.status),
a7f575
-		})
a7f575
-	}
a7f575
-	return &ImportResult{
a7f575
-		Considered:      int(res.considered),
a7f575
-		NoUserID:        int(res.no_user_id),
a7f575
-		Imported:        int(res.imported),
a7f575
-		ImportedRSA:     int(res.imported_rsa),
a7f575
-		Unchanged:       int(res.unchanged),
a7f575
-		NewUserIDs:      int(res.new_user_ids),
a7f575
-		NewSubKeys:      int(res.new_sub_keys),
a7f575
-		NewSignatures:   int(res.new_signatures),
a7f575
-		NewRevocations:  int(res.new_revocations),
a7f575
-		SecretRead:      int(res.secret_read),
a7f575
-		SecretImported:  int(res.secret_imported),
a7f575
-		SecretUnchanged: int(res.secret_unchanged),
a7f575
-		NotImported:     int(res.not_imported),
a7f575
-		Imports:         imports,
a7f575
-	}, nil
a7f575
-}
a7f575
-
a7f575
-type Key struct {
a7f575
-	k C.gpgme_key_t
a7f575
-}
a7f575
-
a7f575
-func newKey() *Key {
a7f575
-	k := &Key{}
a7f575
-	runtime.SetFinalizer(k, (*Key).Release)
a7f575
-	return k
a7f575
-}
a7f575
-
a7f575
-func (k *Key) Release() {
a7f575
-	C.gpgme_key_release(k.k)
a7f575
-	k.k = nil
a7f575
-}
a7f575
-
a7f575
-func (k *Key) Revoked() bool {
a7f575
-	return C.key_revoked(k.k) != 0
a7f575
-}
a7f575
-
a7f575
-func (k *Key) Expired() bool {
a7f575
-	return C.key_expired(k.k) != 0
a7f575
-}
a7f575
-
a7f575
-func (k *Key) Disabled() bool {
a7f575
-	return C.key_disabled(k.k) != 0
a7f575
-}
a7f575
-
a7f575
-func (k *Key) Invalid() bool {
a7f575
-	return C.key_invalid(k.k) != 0
a7f575
-}
a7f575
-
a7f575
-func (k *Key) CanEncrypt() bool {
a7f575
-	return C.key_can_encrypt(k.k) != 0
a7f575
-}
a7f575
-
a7f575
-func (k *Key) CanSign() bool {
a7f575
-	return C.key_can_sign(k.k) != 0
a7f575
-}
a7f575
-
a7f575
-func (k *Key) CanCertify() bool {
a7f575
-	return C.key_can_certify(k.k) != 0
a7f575
-}
a7f575
-
a7f575
-func (k *Key) Secret() bool {
a7f575
-	return C.key_secret(k.k) != 0
a7f575
-}
a7f575
-
a7f575
-func (k *Key) CanAuthenticate() bool {
a7f575
-	return C.key_can_authenticate(k.k) != 0
a7f575
-}
a7f575
-
a7f575
-func (k *Key) IsQualified() bool {
a7f575
-	return C.key_is_qualified(k.k) != 0
a7f575
-}
a7f575
-
a7f575
-func (k *Key) Protocol() Protocol {
a7f575
-	return Protocol(k.k.protocol)
a7f575
-}
a7f575
-
a7f575
-func (k *Key) IssuerSerial() string {
a7f575
-	return C.GoString(k.k.issuer_serial)
a7f575
-}
a7f575
-
a7f575
-func (k *Key) IssuerName() string {
a7f575
-	return C.GoString(k.k.issuer_name)
a7f575
-}
a7f575
-
a7f575
-func (k *Key) ChainID() string {
a7f575
-	return C.GoString(k.k.chain_id)
a7f575
-}
a7f575
-
a7f575
-func (k *Key) OwnerTrust() Validity {
a7f575
-	return Validity(k.k.owner_trust)
a7f575
-}
a7f575
-
a7f575
-func (k *Key) SubKeys() *SubKey {
a7f575
-	if k.k.subkeys == nil {
a7f575
-		return nil
a7f575
-	}
a7f575
-	return &SubKey{k: k.k.subkeys, parent: k}
a7f575
-}
a7f575
-
a7f575
-func (k *Key) UserIDs() *UserID {
a7f575
-	if k.k.uids == nil {
a7f575
-		return nil
a7f575
-	}
a7f575
-	return &UserID{u: k.k.uids, parent: k}
a7f575
-}
a7f575
-
a7f575
-func (k *Key) KeyListMode() KeyListMode {
a7f575
-	return KeyListMode(k.k.keylist_mode)
a7f575
-}
a7f575
-
a7f575
-type SubKey struct {
a7f575
-	k      C.gpgme_subkey_t
a7f575
-	parent *Key // make sure the key is not released when we have a reference to a subkey
a7f575
-}
a7f575
-
a7f575
-func (k *SubKey) Next() *SubKey {
a7f575
-	if k.k.next == nil {
a7f575
-		return nil
a7f575
-	}
a7f575
-	return &SubKey{k: k.k.next, parent: k.parent}
a7f575
-}
a7f575
-
a7f575
-func (k *SubKey) Revoked() bool {
a7f575
-	return C.subkey_revoked(k.k) != 0
a7f575
-}
a7f575
-
a7f575
-func (k *SubKey) Expired() bool {
a7f575
-	return C.subkey_expired(k.k) != 0
a7f575
-}
a7f575
-
a7f575
-func (k *SubKey) Disabled() bool {
a7f575
-	return C.subkey_disabled(k.k) != 0
a7f575
-}
a7f575
-
a7f575
-func (k *SubKey) Invalid() bool {
a7f575
-	return C.subkey_invalid(k.k) != 0
a7f575
-}
a7f575
-
a7f575
-func (k *SubKey) Secret() bool {
a7f575
-	return C.subkey_secret(k.k) != 0
a7f575
-}
a7f575
-
a7f575
-func (k *SubKey) KeyID() string {
a7f575
-	return C.GoString(k.k.keyid)
a7f575
-}
a7f575
-
a7f575
-func (k *SubKey) Fingerprint() string {
a7f575
-	return C.GoString(k.k.fpr)
a7f575
-}
a7f575
-
a7f575
-func (k *SubKey) Created() time.Time {
a7f575
-	if k.k.timestamp <= 0 {
a7f575
-		return time.Time{}
a7f575
-	}
a7f575
-	return time.Unix(int64(k.k.timestamp), 0)
a7f575
-}
a7f575
-
a7f575
-func (k *SubKey) Expires() time.Time {
a7f575
-	if k.k.expires <= 0 {
a7f575
-		return time.Time{}
a7f575
-	}
a7f575
-	return time.Unix(int64(k.k.expires), 0)
a7f575
-}
a7f575
-
a7f575
-func (k *SubKey) CardNumber() string {
a7f575
-	return C.GoString(k.k.card_number)
a7f575
-}
a7f575
-
a7f575
-type UserID struct {
a7f575
-	u      C.gpgme_user_id_t
a7f575
-	parent *Key // make sure the key is not released when we have a reference to a user ID
a7f575
-}
a7f575
-
a7f575
-func (u *UserID) Next() *UserID {
a7f575
-	if u.u.next == nil {
a7f575
-		return nil
a7f575
-	}
a7f575
-	return &UserID{u: u.u.next, parent: u.parent}
a7f575
-}
a7f575
-
a7f575
-func (u *UserID) Revoked() bool {
a7f575
-	return C.uid_revoked(u.u) != 0
a7f575
-}
a7f575
-
a7f575
-func (u *UserID) Invalid() bool {
a7f575
-	return C.uid_invalid(u.u) != 0
a7f575
-}
a7f575
-
a7f575
-func (u *UserID) Validity() Validity {
a7f575
-	return Validity(u.u.validity)
a7f575
-}
a7f575
-
a7f575
-func (u *UserID) UID() string {
a7f575
-	return C.GoString(u.u.uid)
a7f575
-}
a7f575
-
a7f575
-func (u *UserID) Name() string {
a7f575
-	return C.GoString(u.u.name)
a7f575
-}
a7f575
-
a7f575
-func (u *UserID) Comment() string {
a7f575
-	return C.GoString(u.u.comment)
a7f575
-}
a7f575
-
a7f575
-func (u *UserID) Email() string {
a7f575
-	return C.GoString(u.u.email)
a7f575
-}
a7f575
-
a7f575
-// This is somewhat of a horrible hack. We need to unset GPG_AGENT_INFO so that gpgme does not pass --use-agent to GPG.
a7f575
-// os.Unsetenv should be enough, but that only calls the underlying C library (which gpgme uses) if cgo is involved
a7f575
-// - and cgo can't be used in tests. So, provide this helper for test initialization.
a7f575
-func unsetenvGPGAgentInfo() {
a7f575
-	v := C.CString("GPG_AGENT_INFO")
a7f575
-	defer C.free(unsafe.Pointer(v))
a7f575
-	C.unsetenv(v)
a7f575
-}
a7f575
a7f575
From 2c7552e51215d4bf6982b0999df2d67d0bc0de9f Mon Sep 17 00:00:00 2001
a7f575
From: =?UTF-8?q?Miloslav=20Trma=C4=8D?= <mitr@redhat.com>
a7f575
Date: Thu, 20 Feb 2020 16:41:57 +0100
a7f575
Subject: [PATCH 2/2] Update to github.com/mtrmac/gpgme v0.1.2
a7f575
MIME-Version: 1.0
a7f575
Content-Type: text/plain; charset=UTF-8
a7f575
Content-Transfer-Encoding: 8bit
a7f575
a7f575
This fixes CVE-2020-8945 by incorporating
a7f575
https://github.com/proglottis/gpgme/pull/23 .
a7f575
a7f575
Other changes included by the rebase:
a7f575
- Support for gpgme_off_t (~no-op with the RHEL 7 GPGME 1.3.2)
a7f575
- Wrapping a few more GPGME functions (irrelevant if we don't call them)
a7f575
- Better error reporting in Context.GetKey
a7f575
a7f575
Given how invasive the CVE fix is (affecting basically all binding
a7f575
code), it seems safer to just update the package (and be verifiably
a7f575
equivalent with upstream) than to backport and try to back out the few
a7f575
other changes.
a7f575
a7f575
Performed by updating vendor.conf, and
a7f575
$ mkdir -p _build/src/github.com/docker
a7f575
$ ln -s $(pwd) _build/src/github.com/docker/docker
a7f575
$ GOPATH=$(pwd)/_build:$GOPATH vndr github.com/mtrmac/gpgme
a7f575
a7f575
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
a7f575
---
a7f575
 vendor.conf                                   |   2 +-
a7f575
 vendor/github.com/mtrmac/gpgme/README.md      |  13 +
a7f575
 vendor/github.com/mtrmac/gpgme/data.go        |  18 +-
a7f575
 vendor/github.com/mtrmac/gpgme/go.mod         |   3 +
a7f575
 vendor/github.com/mtrmac/gpgme/go_gpgme.c     |  22 ++
a7f575
 vendor/github.com/mtrmac/gpgme/go_gpgme.h     |  12 +
a7f575
 vendor/github.com/mtrmac/gpgme/gpgme.go       | 354 ++++++++++++++----
a7f575
 .../mtrmac/gpgme/unset_agent_info.go          |  18 +
a7f575
 .../mtrmac/gpgme/unset_agent_info_windows.go  |  14 +
a7f575
 9 files changed, 378 insertions(+), 78 deletions(-)
a7f575
 create mode 100644 vendor/github.com/mtrmac/gpgme/README.md
a7f575
 create mode 100644 vendor/github.com/mtrmac/gpgme/go.mod
a7f575
 create mode 100644 vendor/github.com/mtrmac/gpgme/unset_agent_info.go
a7f575
 create mode 100644 vendor/github.com/mtrmac/gpgme/unset_agent_info_windows.go
a7f575
a7f575
diff --git a/vendor.conf b/vendor.conf
a7f575
index d71bcac3ccec..4d4927b0d6f2 100644
a7f575
--- a/vendor.conf
a7f575
+++ b/vendor.conf
a7f575
@@ -147,7 +147,7 @@ github.com/opencontainers/image-spec v1.0.0-rc4
a7f575
 k8s.io/kubernetes 4a3f9c5b19c7ff804cbc1bf37a15c044ca5d2353 https://github.com/openshift/kubernetes
a7f575
 github.com/golang/glog 44145f04b68cf362d9c4df2182967c2275eaefed
a7f575
 github.com/ghodss/yaml 73d445a93680fa1a78ae23a5839bad48f32ba1ee
a7f575
-github.com/mtrmac/gpgme master
a7f575
+github.com/mtrmac/gpgme v0.1.2
a7f575
 github.com/containers/storage master
a7f575
 github.com/opencontainers/go-digest master
a7f575
 
a7f575
diff --git a/vendor/github.com/mtrmac/gpgme/README.md b/vendor/github.com/mtrmac/gpgme/README.md
a7f575
new file mode 100644
a7f575
index 000000000000..4770b82a8e61
a7f575
--- /dev/null
a7f575
+++ b/vendor/github.com/mtrmac/gpgme/README.md
a7f575
@@ -0,0 +1,13 @@
a7f575
+# GPGME (golang)
a7f575
+
a7f575
+Go wrapper for the GPGME library.
a7f575
+
a7f575
+This library is intended for use with desktop applications. If you are looking to add OpenPGP support to a server application I suggest you first look at [golang.org/x/crypto/openpgp](https://godoc.org/golang.org/x/crypto/openpgp).
a7f575
+
a7f575
+## Installation
a7f575
+
a7f575
+    go get -u github.com/proglottis/gpgme
a7f575
+
a7f575
+## Documentation
a7f575
+
a7f575
+* [godoc](https://godoc.org/github.com/proglottis/gpgme)
a7f575
diff --git a/vendor/github.com/mtrmac/gpgme/data.go b/vendor/github.com/mtrmac/gpgme/data.go
a7f575
index eebc9726347d..eee32c0323fc 100644
a7f575
--- a/vendor/github.com/mtrmac/gpgme/data.go
a7f575
+++ b/vendor/github.com/mtrmac/gpgme/data.go
a7f575
@@ -50,25 +50,25 @@ func gogpgme_writefunc(handle, buffer unsafe.Pointer, size C.size_t) C.ssize_t {
a7f575
 }
a7f575
 
a7f575
 //export gogpgme_seekfunc
a7f575
-func gogpgme_seekfunc(handle unsafe.Pointer, offset C.off_t, whence C.int) C.off_t {
a7f575
+func gogpgme_seekfunc(handle unsafe.Pointer, offset C.gpgme_off_t, whence C.int) C.gpgme_off_t {
a7f575
 	d := callbackLookup(uintptr(handle)).(*Data)
a7f575
 	n, err := d.s.Seek(int64(offset), int(whence))
a7f575
 	if err != nil {
a7f575
 		C.gpgme_err_set_errno(C.EIO)
a7f575
 		return -1
a7f575
 	}
a7f575
-	return C.off_t(n)
a7f575
+	return C.gpgme_off_t(n)
a7f575
 }
a7f575
 
a7f575
 // The Data buffer used to communicate with GPGME
a7f575
 type Data struct {
a7f575
-	dh  C.gpgme_data_t
a7f575
+	dh  C.gpgme_data_t // WARNING: Call runtime.KeepAlive(d) after ANY passing of d.dh to C
a7f575
 	buf []byte
a7f575
 	cbs C.struct_gpgme_data_cbs
a7f575
 	r   io.Reader
a7f575
 	w   io.Writer
a7f575
 	s   io.Seeker
a7f575
-	cbc uintptr
a7f575
+	cbc uintptr // WARNING: Call runtime.KeepAlive(d) after ANY use of d.cbc in C (typically via d.dh)
a7f575
 }
a7f575
 
a7f575
 func newData() *Data {
a7f575
@@ -154,12 +154,14 @@ func (d *Data) Close() error {
a7f575
 		callbackDelete(d.cbc)
a7f575
 	}
a7f575
 	_, err := C.gpgme_data_release(d.dh)
a7f575
+	runtime.KeepAlive(d)
a7f575
 	d.dh = nil
a7f575
 	return err
a7f575
 }
a7f575
 
a7f575
 func (d *Data) Write(p []byte) (int, error) {
a7f575
 	n, err := C.gpgme_data_write(d.dh, unsafe.Pointer(&p[0]), C.size_t(len(p)))
a7f575
+	runtime.KeepAlive(d)
a7f575
 	if err != nil {
a7f575
 		return 0, err
a7f575
 	}
a7f575
@@ -171,6 +173,7 @@ func (d *Data) Write(p []byte) (int, error) {
a7f575
 
a7f575
 func (d *Data) Read(p []byte) (int, error) {
a7f575
 	n, err := C.gpgme_data_read(d.dh, unsafe.Pointer(&p[0]), C.size_t(len(p)))
a7f575
+	runtime.KeepAlive(d)
a7f575
 	if err != nil {
a7f575
 		return 0, err
a7f575
 	}
a7f575
@@ -181,11 +184,14 @@ func (d *Data) Read(p []byte) (int, error) {
a7f575
 }
a7f575
 
a7f575
 func (d *Data) Seek(offset int64, whence int) (int64, error) {
a7f575
-	n, err := C.gpgme_data_seek(d.dh, C.off_t(offset), C.int(whence))
a7f575
+	n, err := C.gogpgme_data_seek(d.dh, C.gpgme_off_t(offset), C.int(whence))
a7f575
+	runtime.KeepAlive(d)
a7f575
 	return int64(n), err
a7f575
 }
a7f575
 
a7f575
 // Name returns the associated filename if any
a7f575
 func (d *Data) Name() string {
a7f575
-	return C.GoString(C.gpgme_data_get_file_name(d.dh))
a7f575
+	res := C.GoString(C.gpgme_data_get_file_name(d.dh))
a7f575
+	runtime.KeepAlive(d)
a7f575
+	return res
a7f575
 }
a7f575
diff --git a/vendor/github.com/mtrmac/gpgme/go.mod b/vendor/github.com/mtrmac/gpgme/go.mod
a7f575
new file mode 100644
a7f575
index 000000000000..3dd09c9fbae5
a7f575
--- /dev/null
a7f575
+++ b/vendor/github.com/mtrmac/gpgme/go.mod
a7f575
@@ -0,0 +1,3 @@
a7f575
+module github.com/mtrmac/gpgme
a7f575
+
a7f575
+go 1.11
a7f575
diff --git a/vendor/github.com/mtrmac/gpgme/go_gpgme.c b/vendor/github.com/mtrmac/gpgme/go_gpgme.c
a7f575
index b887574e0cb9..00da3ab304f1 100644
a7f575
--- a/vendor/github.com/mtrmac/gpgme/go_gpgme.c
a7f575
+++ b/vendor/github.com/mtrmac/gpgme/go_gpgme.c
a7f575
@@ -8,6 +8,28 @@ void gogpgme_set_passphrase_cb(gpgme_ctx_t ctx, gpgme_passphrase_cb_t cb, uintpt
a7f575
 	gpgme_set_passphrase_cb(ctx, cb, (void *)handle);
a7f575
 }
a7f575
 
a7f575
+gpgme_off_t gogpgme_data_seek(gpgme_data_t dh, gpgme_off_t offset, int whence) {
a7f575
+	return gpgme_data_seek(dh, offset, whence);
a7f575
+}
a7f575
+
a7f575
+gpgme_error_t gogpgme_op_assuan_transact_ext(
a7f575
+		gpgme_ctx_t ctx,
a7f575
+		char* cmd,
a7f575
+		uintptr_t data_h,
a7f575
+		uintptr_t inquiry_h,
a7f575
+		uintptr_t status_h,
a7f575
+		gpgme_error_t *operr
a7f575
+	){
a7f575
+	return gpgme_op_assuan_transact_ext(
a7f575
+		ctx,
a7f575
+		cmd,
a7f575
+		(gpgme_assuan_data_cb_t)    gogpgme_assuan_data_callback,    (void *)data_h,
a7f575
+		(gpgme_assuan_inquire_cb_t) gogpgme_assuan_inquiry_callback, (void *)inquiry_h,
a7f575
+		(gpgme_assuan_status_cb_t)  gogpgme_assuan_status_callback,  (void *)status_h,
a7f575
+		operr
a7f575
+	);
a7f575
+}
a7f575
+
a7f575
 unsigned int key_revoked(gpgme_key_t k) {
a7f575
 	return k->revoked;
a7f575
 }
a7f575
diff --git a/vendor/github.com/mtrmac/gpgme/go_gpgme.h b/vendor/github.com/mtrmac/gpgme/go_gpgme.h
a7f575
index a3678b127ac7..d4826ab368eb 100644
a7f575
--- a/vendor/github.com/mtrmac/gpgme/go_gpgme.h
a7f575
+++ b/vendor/github.com/mtrmac/gpgme/go_gpgme.h
a7f575
@@ -6,12 +6,24 @@
a7f575
 
a7f575
 #include <gpgme.h>
a7f575
 
a7f575
+/* GPGME_VERSION_NUMBER was introduced in 1.4.0 */
a7f575
+#if !defined(GPGME_VERSION_NUMBER) || GPGME_VERSION_NUMBER < 0x010402
a7f575
+typedef off_t gpgme_off_t; /* Introduced in 1.4.2 */
a7f575
+#endif
a7f575
+
a7f575
 extern ssize_t gogpgme_readfunc(void *handle, void *buffer, size_t size);
a7f575
 extern ssize_t gogpgme_writefunc(void *handle, void *buffer, size_t size);
a7f575
 extern off_t gogpgme_seekfunc(void *handle, off_t offset, int whence);
a7f575
 extern gpgme_error_t gogpgme_passfunc(void *hook, char *uid_hint, char *passphrase_info, int prev_was_bad, int fd);
a7f575
 extern gpgme_error_t gogpgme_data_new_from_cbs(gpgme_data_t *dh, gpgme_data_cbs_t cbs, uintptr_t handle);
a7f575
 extern void gogpgme_set_passphrase_cb(gpgme_ctx_t ctx, gpgme_passphrase_cb_t cb, uintptr_t handle);
a7f575
+extern gpgme_off_t gogpgme_data_seek(gpgme_data_t dh, gpgme_off_t offset, int whence);
a7f575
+
a7f575
+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);
a7f575
+
a7f575
+extern gpgme_error_t gogpgme_assuan_data_callback(void *opaque, void* data, size_t datalen );
a7f575
+extern gpgme_error_t gogpgme_assuan_inquiry_callback(void *opaque, char* name, char* args);
a7f575
+extern gpgme_error_t gogpgme_assuan_status_callback(void *opaque, char* status, char* args);
a7f575
 
a7f575
 extern unsigned int key_revoked(gpgme_key_t k);
a7f575
 extern unsigned int key_expired(gpgme_key_t k);
a7f575
diff --git a/vendor/github.com/mtrmac/gpgme/gpgme.go b/vendor/github.com/mtrmac/gpgme/gpgme.go
a7f575
index 5f1793eab32d..c19b9aebc5cd 100644
a7f575
--- a/vendor/github.com/mtrmac/gpgme/gpgme.go
a7f575
+++ b/vendor/github.com/mtrmac/gpgme/gpgme.go
a7f575
@@ -7,8 +7,8 @@ package gpgme
a7f575
 // #include <gpgme.h>
a7f575
 // #include "go_gpgme.h"
a7f575
 import "C"
a7f575
-
a7f575
 import (
a7f575
+	"fmt"
a7f575
 	"io"
a7f575
 	"os"
a7f575
 	"runtime"
a7f575
@@ -47,9 +47,8 @@ const (
a7f575
 	ProtocolAssuan   Protocol = C.GPGME_PROTOCOL_ASSUAN
a7f575
 	ProtocolG13      Protocol = C.GPGME_PROTOCOL_G13
a7f575
 	ProtocolUIServer Protocol = C.GPGME_PROTOCOL_UISERVER
a7f575
-	// ProtocolSpawn    Protocol = C.GPGME_PROTOCOL_SPAWN // Unavailable in 1.4.3
a7f575
-	ProtocolDefault Protocol = C.GPGME_PROTOCOL_DEFAULT
a7f575
-	ProtocolUnknown Protocol = C.GPGME_PROTOCOL_UNKNOWN
a7f575
+	ProtocolDefault  Protocol = C.GPGME_PROTOCOL_DEFAULT
a7f575
+	ProtocolUnknown  Protocol = C.GPGME_PROTOCOL_UNKNOWN
a7f575
 )
a7f575
 
a7f575
 type PinEntryMode int
a7f575
@@ -69,7 +68,6 @@ const (
a7f575
 	EncryptNoEncryptTo EncryptFlag = C.GPGME_ENCRYPT_NO_ENCRYPT_TO
a7f575
 	EncryptPrepare     EncryptFlag = C.GPGME_ENCRYPT_PREPARE
a7f575
 	EncryptExceptSign  EncryptFlag = C.GPGME_ENCRYPT_EXPECT_SIGN
a7f575
-	// EncryptNoCompress  EncryptFlag = C.GPGME_ENCRYPT_NO_COMPRESS // Unavailable in 1.4.3
a7f575
 )
a7f575
 
a7f575
 type HashAlgo int
a7f575
@@ -83,7 +81,6 @@ const (
a7f575
 	KeyListModeExtern       KeyListMode = C.GPGME_KEYLIST_MODE_EXTERN
a7f575
 	KeyListModeSigs         KeyListMode = C.GPGME_KEYLIST_MODE_SIGS
a7f575
 	KeyListModeSigNotations KeyListMode = C.GPGME_KEYLIST_MODE_SIG_NOTATIONS
a7f575
-	// KeyListModeWithSecret   KeyListMode = C.GPGME_KEYLIST_MODE_WITH_SECRET // Unavailable in 1.4.3
a7f575
 	KeyListModeEphemeral    KeyListMode = C.GPGME_KEYLIST_MODE_EPHEMERAL
a7f575
 	KeyListModeModeValidate KeyListMode = C.GPGME_KEYLIST_MODE_VALIDATE
a7f575
 )
a7f575
@@ -167,39 +164,60 @@ func EngineCheckVersion(p Protocol) error {
a7f575
 }
a7f575
 
a7f575
 type EngineInfo struct {
a7f575
-	info C.gpgme_engine_info_t
a7f575
+	next            *EngineInfo
a7f575
+	protocol        Protocol
a7f575
+	fileName        string
a7f575
+	homeDir         string
a7f575
+	version         string
a7f575
+	requiredVersion string
a7f575
 }
a7f575
 
a7f575
-func (e *EngineInfo) Next() *EngineInfo {
a7f575
-	if e.info.next == nil {
a7f575
-		return nil
a7f575
+func copyEngineInfo(info C.gpgme_engine_info_t) *EngineInfo {
a7f575
+	res := &EngineInfo{
a7f575
+		next:            nil,
a7f575
+		protocol:        Protocol(info.protocol),
a7f575
+		fileName:        C.GoString(info.file_name),
a7f575
+		homeDir:         C.GoString(info.home_dir),
a7f575
+		version:         C.GoString(info.version),
a7f575
+		requiredVersion: C.GoString(info.req_version),
a7f575
+	}
a7f575
+	if info.next != nil {
a7f575
+		res.next = copyEngineInfo(info.next)
a7f575
 	}
a7f575
-	return &EngineInfo{info: e.info.next}
a7f575
+	return res
a7f575
+}
a7f575
+
a7f575
+func (e *EngineInfo) Next() *EngineInfo {
a7f575
+	return e.next
a7f575
 }
a7f575
 
a7f575
 func (e *EngineInfo) Protocol() Protocol {
a7f575
-	return Protocol(e.info.protocol)
a7f575
+	return e.protocol
a7f575
 }
a7f575
 
a7f575
 func (e *EngineInfo) FileName() string {
a7f575
-	return C.GoString(e.info.file_name)
a7f575
+	return e.fileName
a7f575
 }
a7f575
 
a7f575
 func (e *EngineInfo) Version() string {
a7f575
-	return C.GoString(e.info.version)
a7f575
+	return e.version
a7f575
 }
a7f575
 
a7f575
 func (e *EngineInfo) RequiredVersion() string {
a7f575
-	return C.GoString(e.info.req_version)
a7f575
+	return e.requiredVersion
a7f575
 }
a7f575
 
a7f575
 func (e *EngineInfo) HomeDir() string {
a7f575
-	return C.GoString(e.info.home_dir)
a7f575
+	return e.homeDir
a7f575
 }
a7f575
 
a7f575
 func GetEngineInfo() (*EngineInfo, error) {
a7f575
-	info := &EngineInfo{}
a7f575
-	return info, handleError(C.gpgme_get_engine_info(&info.info))
a7f575
+	var cInfo C.gpgme_engine_info_t
a7f575
+	err := handleError(C.gpgme_get_engine_info(&cInfo))
a7f575
+	if err != nil {
a7f575
+		return nil, err
a7f575
+	}
a7f575
+	return copyEngineInfo(cInfo), nil // It is up to the caller not to invalidate cInfo concurrently until this is done.
a7f575
 }
a7f575
 
a7f575
 func SetEngineInfo(proto Protocol, fileName, homeDir string) error {
a7f575
@@ -260,9 +278,9 @@ type Context struct {
a7f575
 	KeyError error
a7f575
 
a7f575
 	callback Callback
a7f575
-	cbc      uintptr
a7f575
+	cbc      uintptr // WARNING: Call runtime.KeepAlive(c) after ANY use of c.cbc in C (typically via c.ctx)
a7f575
 
a7f575
-	ctx C.gpgme_ctx_t
a7f575
+	ctx C.gpgme_ctx_t // WARNING: Call runtime.KeepAlive(c) after ANY passing of c.ctx to C
a7f575
 }
a7f575
 
a7f575
 func New() (*Context, error) {
a7f575
@@ -280,49 +298,68 @@ func (c *Context) Release() {
a7f575
 		callbackDelete(c.cbc)
a7f575
 	}
a7f575
 	C.gpgme_release(c.ctx)
a7f575
+	runtime.KeepAlive(c)
a7f575
 	c.ctx = nil
a7f575
 }
a7f575
 
a7f575
 func (c *Context) SetArmor(yes bool) {
a7f575
 	C.gpgme_set_armor(c.ctx, cbool(yes))
a7f575
+	runtime.KeepAlive(c)
a7f575
 }
a7f575
 
a7f575
 func (c *Context) Armor() bool {
a7f575
-	return C.gpgme_get_armor(c.ctx) != 0
a7f575
+	res := C.gpgme_get_armor(c.ctx) != 0
a7f575
+	runtime.KeepAlive(c)
a7f575
+	return res
a7f575
 }
a7f575
 
a7f575
 func (c *Context) SetTextMode(yes bool) {
a7f575
 	C.gpgme_set_textmode(c.ctx, cbool(yes))
a7f575
+	runtime.KeepAlive(c)
a7f575
 }
a7f575
 
a7f575
 func (c *Context) TextMode() bool {
a7f575
-	return C.gpgme_get_textmode(c.ctx) != 0
a7f575
+	res := C.gpgme_get_textmode(c.ctx) != 0
a7f575
+	runtime.KeepAlive(c)
a7f575
+	return res
a7f575
 }
a7f575
 
a7f575
 func (c *Context) SetProtocol(p Protocol) error {
a7f575
-	return handleError(C.gpgme_set_protocol(c.ctx, C.gpgme_protocol_t(p)))
a7f575
+	err := handleError(C.gpgme_set_protocol(c.ctx, C.gpgme_protocol_t(p)))
a7f575
+	runtime.KeepAlive(c)
a7f575
+	return err
a7f575
 }
a7f575
 
a7f575
 func (c *Context) Protocol() Protocol {
a7f575
-	return Protocol(C.gpgme_get_protocol(c.ctx))
a7f575
+	res := Protocol(C.gpgme_get_protocol(c.ctx))
a7f575
+	runtime.KeepAlive(c)
a7f575
+	return res
a7f575
 }
a7f575
 
a7f575
 func (c *Context) SetKeyListMode(m KeyListMode) error {
a7f575
-	return handleError(C.gpgme_set_keylist_mode(c.ctx, C.gpgme_keylist_mode_t(m)))
a7f575
+	err := handleError(C.gpgme_set_keylist_mode(c.ctx, C.gpgme_keylist_mode_t(m)))
a7f575
+	runtime.KeepAlive(c)
a7f575
+	return err
a7f575
 }
a7f575
 
a7f575
 func (c *Context) KeyListMode() KeyListMode {
a7f575
-	return KeyListMode(C.gpgme_get_keylist_mode(c.ctx))
a7f575
+	res := KeyListMode(C.gpgme_get_keylist_mode(c.ctx))
a7f575
+	runtime.KeepAlive(c)
a7f575
+	return res
a7f575
 }
a7f575
 
a7f575
 // Unavailable in 1.3.2:
a7f575
 // func (c *Context) SetPinEntryMode(m PinEntryMode) error {
a7f575
-// 	return handleError(C.gpgme_set_pinentry_mode(c.ctx, C.gpgme_pinentry_mode_t(m)))
a7f575
+// 	err := handleError(C.gpgme_set_pinentry_mode(c.ctx, C.gpgme_pinentry_mode_t(m)))
a7f575
+// 	runtime.KeepAlive(c)
a7f575
+// 	return err
a7f575
 // }
a7f575
 
a7f575
 // Unavailable in 1.3.2:
a7f575
 // func (c *Context) PinEntryMode() PinEntryMode {
a7f575
-// 	return PinEntryMode(C.gpgme_get_pinentry_mode(c.ctx))
a7f575
+// 	res := PinEntryMode(C.gpgme_get_pinentry_mode(c.ctx))
a7f575
+// 	runtime.KeepAlive(c)
a7f575
+// 	return res
a7f575
 // }
a7f575
 
a7f575
 func (c *Context) SetCallback(callback Callback) error {
a7f575
@@ -339,11 +376,17 @@ func (c *Context) SetCallback(callback Callback) error {
a7f575
 		c.cbc = 0
a7f575
 		_, err = C.gogpgme_set_passphrase_cb(c.ctx, nil, 0)
a7f575
 	}
a7f575
+	runtime.KeepAlive(c)
a7f575
 	return err
a7f575
 }
a7f575
 
a7f575
 func (c *Context) EngineInfo() *EngineInfo {
a7f575
-	return &EngineInfo{info: C.gpgme_ctx_get_engine_info(c.ctx)}
a7f575
+	cInfo := C.gpgme_ctx_get_engine_info(c.ctx)
a7f575
+	runtime.KeepAlive(c)
a7f575
+	// NOTE: c must be live as long as we are accessing cInfo.
a7f575
+	res := copyEngineInfo(cInfo)
a7f575
+	runtime.KeepAlive(c) // for accesses to cInfo
a7f575
+	return res
a7f575
 }
a7f575
 
a7f575
 func (c *Context) SetEngineInfo(proto Protocol, fileName, homeDir string) error {
a7f575
@@ -356,19 +399,23 @@ func (c *Context) SetEngineInfo(proto Protocol, fileName, homeDir string) error
a7f575
 		chome = C.CString(homeDir)
a7f575
 		defer C.free(unsafe.Pointer(chome))
a7f575
 	}
a7f575
-	return handleError(C.gpgme_ctx_set_engine_info(c.ctx, C.gpgme_protocol_t(proto), cfn, chome))
a7f575
+	err := handleError(C.gpgme_ctx_set_engine_info(c.ctx, C.gpgme_protocol_t(proto), cfn, chome))
a7f575
+	runtime.KeepAlive(c)
a7f575
+	return err
a7f575
 }
a7f575
 
a7f575
 func (c *Context) KeyListStart(pattern string, secretOnly bool) error {
a7f575
 	cpattern := C.CString(pattern)
a7f575
 	defer C.free(unsafe.Pointer(cpattern))
a7f575
-	err := C.gpgme_op_keylist_start(c.ctx, cpattern, cbool(secretOnly))
a7f575
-	return handleError(err)
a7f575
+	err := handleError(C.gpgme_op_keylist_start(c.ctx, cpattern, cbool(secretOnly)))
a7f575
+	runtime.KeepAlive(c)
a7f575
+	return err
a7f575
 }
a7f575
 
a7f575
 func (c *Context) KeyListNext() bool {
a7f575
 	c.Key = newKey()
a7f575
 	err := handleError(C.gpgme_op_keylist_next(c.ctx, &c.Key.k))
a7f575
+	runtime.KeepAlive(c) // implies runtime.KeepAlive(c.Key)
a7f575
 	if err != nil {
a7f575
 		if e, ok := err.(Error); ok && e.Code() == ErrorEOF {
a7f575
 			c.KeyError = nil
a7f575
@@ -382,22 +429,43 @@ func (c *Context) KeyListNext() bool {
a7f575
 }
a7f575
 
a7f575
 func (c *Context) KeyListEnd() error {
a7f575
-	return handleError(C.gpgme_op_keylist_end(c.ctx))
a7f575
+	err := handleError(C.gpgme_op_keylist_end(c.ctx))
a7f575
+	runtime.KeepAlive(c)
a7f575
+	return err
a7f575
 }
a7f575
 
a7f575
 func (c *Context) GetKey(fingerprint string, secret bool) (*Key, error) {
a7f575
 	key := newKey()
a7f575
 	cfpr := C.CString(fingerprint)
a7f575
 	defer C.free(unsafe.Pointer(cfpr))
a7f575
-	return key, handleError(C.gpgme_get_key(c.ctx, cfpr, &key.k, cbool(secret)))
a7f575
+	err := handleError(C.gpgme_get_key(c.ctx, cfpr, &key.k, cbool(secret)))
a7f575
+	runtime.KeepAlive(c)
a7f575
+	runtime.KeepAlive(key)
a7f575
+	keyKIsNil := key.k == nil
a7f575
+	runtime.KeepAlive(key)
a7f575
+	if e, ok := err.(Error); keyKIsNil && ok && e.Code() == ErrorEOF {
a7f575
+		return nil, fmt.Errorf("key %q not found", fingerprint)
a7f575
+	}
a7f575
+	if err != nil {
a7f575
+		return nil, err
a7f575
+	}
a7f575
+	return key, nil
a7f575
 }
a7f575
 
a7f575
 func (c *Context) Decrypt(ciphertext, plaintext *Data) error {
a7f575
-	return handleError(C.gpgme_op_decrypt(c.ctx, ciphertext.dh, plaintext.dh))
a7f575
+	err := handleError(C.gpgme_op_decrypt(c.ctx, ciphertext.dh, plaintext.dh))
a7f575
+	runtime.KeepAlive(c)
a7f575
+	runtime.KeepAlive(ciphertext)
a7f575
+	runtime.KeepAlive(plaintext)
a7f575
+	return err
a7f575
 }
a7f575
 
a7f575
 func (c *Context) DecryptVerify(ciphertext, plaintext *Data) error {
a7f575
-	return handleError(C.gpgme_op_decrypt_verify(c.ctx, ciphertext.dh, plaintext.dh))
a7f575
+	err := handleError(C.gpgme_op_decrypt_verify(c.ctx, ciphertext.dh, plaintext.dh))
a7f575
+	runtime.KeepAlive(c)
a7f575
+	runtime.KeepAlive(ciphertext)
a7f575
+	runtime.KeepAlive(plaintext)
a7f575
+	return err
a7f575
 }
a7f575
 
a7f575
 type Signature struct {
a7f575
@@ -424,10 +492,20 @@ func (c *Context) Verify(sig, signedText, plain *Data) (string, []Signature, err
a7f575
 		plainPtr = plain.dh
a7f575
 	}
a7f575
 	err := handleError(C.gpgme_op_verify(c.ctx, sig.dh, signedTextPtr, plainPtr))
a7f575
+	runtime.KeepAlive(c)
a7f575
+	runtime.KeepAlive(sig)
a7f575
+	if signedText != nil {
a7f575
+		runtime.KeepAlive(signedText)
a7f575
+	}
a7f575
+	if plain != nil {
a7f575
+		runtime.KeepAlive(plain)
a7f575
+	}
a7f575
 	if err != nil {
a7f575
 		return "", nil, err
a7f575
 	}
a7f575
 	res := C.gpgme_op_verify_result(c.ctx)
a7f575
+	runtime.KeepAlive(c)
a7f575
+	// NOTE: c must be live as long as we are accessing res.
a7f575
 	sigs := []Signature{}
a7f575
 	for s := res.signatures; s != nil; s = s.next {
a7f575
 		sig := Signature{
a7f575
@@ -447,7 +525,9 @@ func (c *Context) Verify(sig, signedText, plain *Data) (string, []Signature, err
a7f575
 		}
a7f575
 		sigs = append(sigs, sig)
a7f575
 	}
a7f575
-	return C.GoString(res.file_name), sigs, nil
a7f575
+	fileName := C.GoString(res.file_name)
a7f575
+	runtime.KeepAlive(c) // for all accesses to res above
a7f575
+	return fileName, sigs, nil
a7f575
 }
a7f575
 
a7f575
 func (c *Context) Encrypt(recipients []*Key, flags EncryptFlag, plaintext, ciphertext *Data) error {
a7f575
@@ -459,18 +539,116 @@ func (c *Context) Encrypt(recipients []*Key, flags EncryptFlag, plaintext, ciphe
a7f575
 		*ptr = recipients[i].k
a7f575
 	}
a7f575
 	err := C.gpgme_op_encrypt(c.ctx, (*C.gpgme_key_t)(recp), C.gpgme_encrypt_flags_t(flags), plaintext.dh, ciphertext.dh)
a7f575
+	runtime.KeepAlive(c)
a7f575
+	runtime.KeepAlive(recipients)
a7f575
+	runtime.KeepAlive(plaintext)
a7f575
+	runtime.KeepAlive(ciphertext)
a7f575
 	return handleError(err)
a7f575
 }
a7f575
 
a7f575
 func (c *Context) Sign(signers []*Key, plain, sig *Data, mode SigMode) error {
a7f575
 	C.gpgme_signers_clear(c.ctx)
a7f575
+	runtime.KeepAlive(c)
a7f575
 	for _, k := range signers {
a7f575
-		if err := handleError(C.gpgme_signers_add(c.ctx, k.k)); err != nil {
a7f575
+		err := handleError(C.gpgme_signers_add(c.ctx, k.k))
a7f575
+		runtime.KeepAlive(c)
a7f575
+		runtime.KeepAlive(k)
a7f575
+		if err != nil {
a7f575
 			C.gpgme_signers_clear(c.ctx)
a7f575
+			runtime.KeepAlive(c)
a7f575
 			return err
a7f575
 		}
a7f575
 	}
a7f575
-	return handleError(C.gpgme_op_sign(c.ctx, plain.dh, sig.dh, C.gpgme_sig_mode_t(mode)))
a7f575
+	err := handleError(C.gpgme_op_sign(c.ctx, plain.dh, sig.dh, C.gpgme_sig_mode_t(mode)))
a7f575
+	runtime.KeepAlive(c)
a7f575
+	runtime.KeepAlive(plain)
a7f575
+	runtime.KeepAlive(sig)
a7f575
+	return err
a7f575
+}
a7f575
+
a7f575
+type AssuanDataCallback func(data []byte) error
a7f575
+type AssuanInquireCallback func(name, args string) error
a7f575
+type AssuanStatusCallback func(status, args string) error
a7f575
+
a7f575
+// AssuanSend sends a raw Assuan command to gpg-agent
a7f575
+func (c *Context) AssuanSend(
a7f575
+	cmd string,
a7f575
+	data AssuanDataCallback,
a7f575
+	inquiry AssuanInquireCallback,
a7f575
+	status AssuanStatusCallback,
a7f575
+) error {
a7f575
+	var operr C.gpgme_error_t
a7f575
+
a7f575
+	dataPtr := callbackAdd(&data)
a7f575
+	inquiryPtr := callbackAdd(&inquiry)
a7f575
+	statusPtr := callbackAdd(&status)
a7f575
+	cmdCStr := C.CString(cmd)
a7f575
+	defer C.free(unsafe.Pointer(cmdCStr))
a7f575
+	err := C.gogpgme_op_assuan_transact_ext(
a7f575
+		c.ctx,
a7f575
+		cmdCStr,
a7f575
+		C.uintptr_t(dataPtr),
a7f575
+		C.uintptr_t(inquiryPtr),
a7f575
+		C.uintptr_t(statusPtr),
a7f575
+		&operr,
a7f575
+	)
a7f575
+	runtime.KeepAlive(c)
a7f575
+
a7f575
+	if handleError(operr) != nil {
a7f575
+		return handleError(operr)
a7f575
+	}
a7f575
+	return handleError(err)
a7f575
+}
a7f575
+
a7f575
+//export gogpgme_assuan_data_callback
a7f575
+func gogpgme_assuan_data_callback(handle unsafe.Pointer, data unsafe.Pointer, datalen C.size_t) C.gpgme_error_t {
a7f575
+	c := callbackLookup(uintptr(handle)).(*AssuanDataCallback)
a7f575
+	if *c == nil {
a7f575
+		return 0
a7f575
+	}
a7f575
+	(*c)(C.GoBytes(data, C.int(datalen)))
a7f575
+	return 0
a7f575
+}
a7f575
+
a7f575
+//export gogpgme_assuan_inquiry_callback
a7f575
+func gogpgme_assuan_inquiry_callback(handle unsafe.Pointer, cName *C.char, cArgs *C.char) C.gpgme_error_t {
a7f575
+	name := C.GoString(cName)
a7f575
+	args := C.GoString(cArgs)
a7f575
+	c := callbackLookup(uintptr(handle)).(*AssuanInquireCallback)
a7f575
+	if *c == nil {
a7f575
+		return 0
a7f575
+	}
a7f575
+	(*c)(name, args)
a7f575
+	return 0
a7f575
+}
a7f575
+
a7f575
+//export gogpgme_assuan_status_callback
a7f575
+func gogpgme_assuan_status_callback(handle unsafe.Pointer, cStatus *C.char, cArgs *C.char) C.gpgme_error_t {
a7f575
+	status := C.GoString(cStatus)
a7f575
+	args := C.GoString(cArgs)
a7f575
+	c := callbackLookup(uintptr(handle)).(*AssuanStatusCallback)
a7f575
+	if *c == nil {
a7f575
+		return 0
a7f575
+	}
a7f575
+	(*c)(status, args)
a7f575
+	return 0
a7f575
+}
a7f575
+
a7f575
+// ExportModeFlags defines how keys are exported from Export
a7f575
+type ExportModeFlags uint
a7f575
+
a7f575
+const (
a7f575
+	ExportModeExtern  ExportModeFlags = C.GPGME_EXPORT_MODE_EXTERN
a7f575
+	ExportModeMinimal ExportModeFlags = C.GPGME_EXPORT_MODE_MINIMAL
a7f575
+)
a7f575
+
a7f575
+func (c *Context) Export(pattern string, mode ExportModeFlags, data *Data) error {
a7f575
+	pat := C.CString(pattern)
a7f575
+	defer C.free(unsafe.Pointer(pat))
a7f575
+	err := handleError(C.gpgme_op_export(c.ctx, pat, C.gpgme_export_mode_t(mode), data.dh))
a7f575
+	runtime.KeepAlive(c)
a7f575
+	runtime.KeepAlive(data)
a7f575
+	return err
a7f575
 }
a7f575
 
a7f575
 // ImportStatusFlags describes the type of ImportStatus.Status. The C API in gpgme.h simply uses "unsigned".
a7f575
@@ -509,10 +687,14 @@ type ImportResult struct {
a7f575
 
a7f575
 func (c *Context) Import(keyData *Data) (*ImportResult, error) {
a7f575
 	err := handleError(C.gpgme_op_import(c.ctx, keyData.dh))
a7f575
+	runtime.KeepAlive(c)
a7f575
+	runtime.KeepAlive(keyData)
a7f575
 	if err != nil {
a7f575
 		return nil, err
a7f575
 	}
a7f575
 	res := C.gpgme_op_import_result(c.ctx)
a7f575
+	runtime.KeepAlive(c)
a7f575
+	// NOTE: c must be live as long as we are accessing res.
a7f575
 	imports := []ImportStatus{}
a7f575
 	for s := res.imports; s != nil; s = s.next {
a7f575
 		imports = append(imports, ImportStatus{
a7f575
@@ -521,7 +703,7 @@ func (c *Context) Import(keyData *Data) (*ImportResult, error) {
a7f575
 			Status:      ImportStatusFlags(s.status),
a7f575
 		})
a7f575
 	}
a7f575
-	return &ImportResult{
a7f575
+	importResult := &ImportResult{
a7f575
 		Considered:      int(res.considered),
a7f575
 		NoUserID:        int(res.no_user_id),
a7f575
 		Imported:        int(res.imported),
a7f575
@@ -536,11 +718,13 @@ func (c *Context) Import(keyData *Data) (*ImportResult, error) {
a7f575
 		SecretUnchanged: int(res.secret_unchanged),
a7f575
 		NotImported:     int(res.not_imported),
a7f575
 		Imports:         imports,
a7f575
-	}, nil
a7f575
+	}
a7f575
+	runtime.KeepAlive(c) // for all accesses to res above
a7f575
+	return importResult, nil
a7f575
 }
a7f575
 
a7f575
 type Key struct {
a7f575
-	k C.gpgme_key_t
a7f575
+	k C.gpgme_key_t // WARNING: Call Runtime.KeepAlive(k) after ANY passing of k.k to C
a7f575
 }
a7f575
 
a7f575
 func newKey() *Key {
a7f575
@@ -551,85 +735,122 @@ func newKey() *Key {
a7f575
 
a7f575
 func (k *Key) Release() {
a7f575
 	C.gpgme_key_release(k.k)
a7f575
+	runtime.KeepAlive(k)
a7f575
 	k.k = nil
a7f575
 }
a7f575
 
a7f575
 func (k *Key) Revoked() bool {
a7f575
-	return C.key_revoked(k.k) != 0
a7f575
+	res := C.key_revoked(k.k) != 0
a7f575
+	runtime.KeepAlive(k)
a7f575
+	return res
a7f575
 }
a7f575
 
a7f575
 func (k *Key) Expired() bool {
a7f575
-	return C.key_expired(k.k) != 0
a7f575
+	res := C.key_expired(k.k) != 0
a7f575
+	runtime.KeepAlive(k)
a7f575
+	return res
a7f575
 }
a7f575
 
a7f575
 func (k *Key) Disabled() bool {
a7f575
-	return C.key_disabled(k.k) != 0
a7f575
+	res := C.key_disabled(k.k) != 0
a7f575
+	runtime.KeepAlive(k)
a7f575
+	return res
a7f575
 }
a7f575
 
a7f575
 func (k *Key) Invalid() bool {
a7f575
-	return C.key_invalid(k.k) != 0
a7f575
+	res := C.key_invalid(k.k) != 0
a7f575
+	runtime.KeepAlive(k)
a7f575
+	return res
a7f575
 }
a7f575
 
a7f575
 func (k *Key) CanEncrypt() bool {
a7f575
-	return C.key_can_encrypt(k.k) != 0
a7f575
+	res := C.key_can_encrypt(k.k) != 0
a7f575
+	runtime.KeepAlive(k)
a7f575
+	return res
a7f575
 }
a7f575
 
a7f575
 func (k *Key) CanSign() bool {
a7f575
-	return C.key_can_sign(k.k) != 0
a7f575
+	res := C.key_can_sign(k.k) != 0
a7f575
+	runtime.KeepAlive(k)
a7f575
+	return res
a7f575
 }
a7f575
 
a7f575
 func (k *Key) CanCertify() bool {
a7f575
-	return C.key_can_certify(k.k) != 0
a7f575
+	res := C.key_can_certify(k.k) != 0
a7f575
+	runtime.KeepAlive(k)
a7f575
+	return res
a7f575
 }
a7f575
 
a7f575
 func (k *Key) Secret() bool {
a7f575
-	return C.key_secret(k.k) != 0
a7f575
+	res := C.key_secret(k.k) != 0
a7f575
+	runtime.KeepAlive(k)
a7f575
+	return res
a7f575
 }
a7f575
 
a7f575
 func (k *Key) CanAuthenticate() bool {
a7f575
-	return C.key_can_authenticate(k.k) != 0
a7f575
+	res := C.key_can_authenticate(k.k) != 0
a7f575
+	runtime.KeepAlive(k)
a7f575
+	return res
a7f575
 }
a7f575
 
a7f575
 func (k *Key) IsQualified() bool {
a7f575
-	return C.key_is_qualified(k.k) != 0
a7f575
+	res := C.key_is_qualified(k.k) != 0
a7f575
+	runtime.KeepAlive(k)
a7f575
+	return res
a7f575
 }
a7f575
 
a7f575
 func (k *Key) Protocol() Protocol {
a7f575
-	return Protocol(k.k.protocol)
a7f575
+	res := Protocol(k.k.protocol)
a7f575
+	runtime.KeepAlive(k)
a7f575
+	return res
a7f575
 }
a7f575
 
a7f575
 func (k *Key) IssuerSerial() string {
a7f575
-	return C.GoString(k.k.issuer_serial)
a7f575
+	res := C.GoString(k.k.issuer_serial)
a7f575
+	runtime.KeepAlive(k)
a7f575
+	return res
a7f575
 }
a7f575
 
a7f575
 func (k *Key) IssuerName() string {
a7f575
-	return C.GoString(k.k.issuer_name)
a7f575
+	res := C.GoString(k.k.issuer_name)
a7f575
+	runtime.KeepAlive(k)
a7f575
+	return res
a7f575
 }
a7f575
 
a7f575
 func (k *Key) ChainID() string {
a7f575
-	return C.GoString(k.k.chain_id)
a7f575
+	res := C.GoString(k.k.chain_id)
a7f575
+	runtime.KeepAlive(k)
a7f575
+	return res
a7f575
 }
a7f575
 
a7f575
 func (k *Key) OwnerTrust() Validity {
a7f575
-	return Validity(k.k.owner_trust)
a7f575
+	res := Validity(k.k.owner_trust)
a7f575
+	runtime.KeepAlive(k)
a7f575
+	return res
a7f575
 }
a7f575
 
a7f575
 func (k *Key) SubKeys() *SubKey {
a7f575
-	if k.k.subkeys == nil {
a7f575
+	subKeys := k.k.subkeys
a7f575
+	runtime.KeepAlive(k)
a7f575
+	if subKeys == nil {
a7f575
 		return nil
a7f575
 	}
a7f575
-	return &SubKey{k: k.k.subkeys, parent: k}
a7f575
+	return &SubKey{k: subKeys, parent: k} // The parent: k reference ensures subKeys remains valid
a7f575
 }
a7f575
 
a7f575
 func (k *Key) UserIDs() *UserID {
a7f575
-	if k.k.uids == nil {
a7f575
+	uids := k.k.uids
a7f575
+	runtime.KeepAlive(k)
a7f575
+	if uids == nil {
a7f575
 		return nil
a7f575
 	}
a7f575
-	return &UserID{u: k.k.uids, parent: k}
a7f575
+	return &UserID{u: uids, parent: k} // The parent: k reference ensures uids remains valid
a7f575
 }
a7f575
 
a7f575
 func (k *Key) KeyListMode() KeyListMode {
a7f575
-	return KeyListMode(k.k.keylist_mode)
a7f575
+	res := KeyListMode(k.k.keylist_mode)
a7f575
+	runtime.KeepAlive(k)
a7f575
+	return res
a7f575
 }
a7f575
 
a7f575
 type SubKey struct {
a7f575
@@ -729,12 +950,3 @@ func (u *UserID) Comment() string {
a7f575
 func (u *UserID) Email() string {
a7f575
 	return C.GoString(u.u.email)
a7f575
 }
a7f575
-
a7f575
-// This is somewhat of a horrible hack. We need to unset GPG_AGENT_INFO so that gpgme does not pass --use-agent to GPG.
a7f575
-// os.Unsetenv should be enough, but that only calls the underlying C library (which gpgme uses) if cgo is involved
a7f575
-// - and cgo can't be used in tests. So, provide this helper for test initialization.
a7f575
-func unsetenvGPGAgentInfo() {
a7f575
-	v := C.CString("GPG_AGENT_INFO")
a7f575
-	defer C.free(unsafe.Pointer(v))
a7f575
-	C.unsetenv(v)
a7f575
-}
a7f575
diff --git a/vendor/github.com/mtrmac/gpgme/unset_agent_info.go b/vendor/github.com/mtrmac/gpgme/unset_agent_info.go
a7f575
new file mode 100644
a7f575
index 000000000000..986aca59f67b
a7f575
--- /dev/null
a7f575
+++ b/vendor/github.com/mtrmac/gpgme/unset_agent_info.go
a7f575
@@ -0,0 +1,18 @@
a7f575
+// +build !windows
a7f575
+
a7f575
+package gpgme
a7f575
+
a7f575
+// #include <stdlib.h>
a7f575
+import "C"
a7f575
+import (
a7f575
+	"unsafe"
a7f575
+)
a7f575
+
a7f575
+// This is somewhat of a horrible hack. We need to unset GPG_AGENT_INFO so that gpgme does not pass --use-agent to GPG.
a7f575
+// os.Unsetenv should be enough, but that only calls the underlying C library (which gpgme uses) if cgo is involved
a7f575
+// - and cgo can't be used in tests. So, provide this helper for test initialization.
a7f575
+func unsetenvGPGAgentInfo() {
a7f575
+	v := C.CString("GPG_AGENT_INFO")
a7f575
+	defer C.free(unsafe.Pointer(v))
a7f575
+	C.unsetenv(v)
a7f575
+}
a7f575
diff --git a/vendor/github.com/mtrmac/gpgme/unset_agent_info_windows.go b/vendor/github.com/mtrmac/gpgme/unset_agent_info_windows.go
a7f575
new file mode 100644
a7f575
index 000000000000..431ec86d3c24
a7f575
--- /dev/null
a7f575
+++ b/vendor/github.com/mtrmac/gpgme/unset_agent_info_windows.go
a7f575
@@ -0,0 +1,14 @@
a7f575
+package gpgme
a7f575
+
a7f575
+// #include <stdlib.h>
a7f575
+import "C"
a7f575
+import (
a7f575
+	"unsafe"
a7f575
+)
a7f575
+
a7f575
+// unsetenv is not available in mingw
a7f575
+func unsetenvGPGAgentInfo() {
a7f575
+	v := C.CString("GPG_AGENT_INFO=")
a7f575
+	defer C.free(unsafe.Pointer(v))
a7f575
+	C.putenv(v)
a7f575
+}