gpgme:在签署数据时选择私钥

9
使用gpgme(gpg / gnupg的开发库),我正在尝试签署一些数据。在密钥环中,我有超过1个私钥,因此我想选择正确的私钥。这会导致错误:“不可用的秘密密钥(117440566)”。该密钥是使用gnupg2生成的。在使用gnupg时也会出现此问题。
sec   1024R/14B7E8E6 2015-05-27
      Key fingerprint = 95C7 6C5E F839 43DA 2F32  2CF4 D2C2 5144 14B7 E8E6
uid                  testkey2 (testkey2) <test@vanheusden.com>
ssb   1024R/ED8059EA 2015-05-27

pub  rsa1024/14B7E8E6
     created: 2015-05-27  expires: never       usage: SC
     trust: ultimate      validity: ultimate
sub  rsa1024/ED8059EA
     created: 2015-05-27  expires: never       usage: E
sub  rsa1024/74D6F5C6
     created: 2015-05-31  expires: never       usage: S

首先,我会检查所选密钥是否有私钥:

gpgme_op_keylist_start(..., ..., 1);
if (gpgme_op_keylist_nex() == GPG_ERR_NO_ERROR) { proceed }

进行签名:

gpgme_new()
gpgme_set_pinentry_mode(GPGME_PINENTRY_MODE_LOOPBACK) // yes i installed v2.1
gpgme_set_passphrase_cb()
/* ...binary to gpgme_data_t... */
gpgme_data_set_encoding(GPGME_DATA_ENCODING_BINARY)
gpgme_signers_clear()
gpgme_signers_add()   // <- that key that I checked for existance earlier
if (gpgme_signers_count() != 1) { fail(); } // sanity check
gpgme_op_encrypt_sign(ctx, recipient, GPGME_ENCRYPT_ALWAYS_TRUST /* FIXME */, data_in, sig);

现在使用gpgme_op_encrypt_sign时总是出现“不可用的密钥(117440566)”错误。

软件版本:

gnupg    1.4.18-7
gnupg-agent      2.1.4-1
gnupg2   2.1.4-1
libgpgme++2      4:4.14.2-2+b1
libgpgme11:amd64         1.5.1-6
libgpgme11-dev   1.5.1-6
python-gnupginterface    0.3.2-9.1

我启用了调试跟踪,但它并没有对我有太大的帮助:

<0x1927>  gpgme_debug: level=4
<0x1927>  gpgme_check_version: call: 0=(nil), req_version=(null), VERSION=1.5.1
<0x1927>  gpgme_check_version_internal: call: 0=(nil), req_version=(null), offset_sig_validity=60
<0x1927>  gpgme_set_locale: enter: ctx=(nil), category=0, value=C
<0x1927>  gpgme_set_locale: leave
<0x1927>  gpgme_set_locale: enter: ctx=(nil), category=5, value=C
<0x1927>  gpgme_set_locale: leave
<0x1927>  gpgme-dinfo: gpgconf='/usr/bin/gpgconf'
<0x1927>  gpgme-dinfo:     gpg='/usr/bin/gpg2'
<0x1927>  gpgme-dinfo:   gpgsm='/usr/bin/gpgsm'
<0x1927>  gpgme-dinfo: homedir='/home/folkert/.gnupg'
<0x1927>  gpgme-dinfo:   agent='/home/folkert/.gnupg/S.gpg-agent'
<0x1927>  gpgme-dinfo:   uisrv='/home/folkert/.gnupg/S.uiserver'
<0x1927>  gpgme_new: enter: r_ctx=0x7fff5afd07a8
<0x1927>  gpgme_new: leave: ctx=0x20c0810
<0x1927>  gpgme_op_keylist_start: enter: ctx=0x20c0810, pattern=0BF38589, secret_only=1
<0x1927>    _gpgme_add_io_cb: call: ctx=0x20c0810, fd 4, dir=1 -> tag=0x20c26b0
<0x1927>    _gpgme_add_io_cb: call: ctx=0x20c0810, fd 6, dir=1 -> tag=0x20c2800
<0x1927>    gpgme:gpg_io_event: call: gpg=0x20c0c10, event 0x7fd8b1a20ad0, type 0, type_data (nil)
<0x1927>  gpgme_op_keylist_start: leave
<0x1927>  gpgme_op_keylist_next: enter: ctx=0x20c0810
<0x1927>    _gpgme_run_io_cb: call: item=0x20c2820, need to check
<0x1927>    _gpgme_run_io_cb: call: item=0x20c2820, handler (0x20c0c10, 6)
<0x1927>    gpgme:keylist_colon_handler: call: ctx=0x20c0810, key = (nil), line = sec:u:2048:1:CC73A8A60BF38589:1433443717:::u:::scESC::::::
<0x1927>    gpgme:keylist_colon_handler: call: ctx=0x20c0810, key = 0x20c2850, line = fpr:::::::::20CD3FF80DA6C1E46CD9F135CC73A8A60BF38589:
<0x1927>    gpgme:keylist_colon_handler: call: ctx=0x20c0810, key = 0x20c2850, line = uid:u::::1433443717::9963CFDE0C8920AD077B06A281992C4008E67E4F::testkey3 (testkey3) <test@vanheusden.com>:
<0x1927>    gpgme:keylist_colon_handler: call: ctx=0x20c0810, key = 0x20c2850, line = ssb:u:2048:1:22317805D48C1491:1433443717::::::e::::::
<0x1927>    gpgme:keylist_colon_handler: call: ctx=0x20c0810, key = 0x20c2850, line = fpr:::::::::FB6FFB7D8BEC710A745DE86C22317805D48C1491:
<0x1927>    _gpgme_run_io_cb: call: item=0x20c26d0, need to check
<0x1927>    _gpgme_run_io_cb: call: item=0x20c26d0, handler (0x20c0c10, 4)
<0x1927>      _gpgme_remove_io_cb: call: data=0x20c26b0, setting fd 0x4 (item=0x20c26d0) done
<0x1927>    _gpgme_run_io_cb: call: item=0x20c2820, need to check
<0x1927>    _gpgme_run_io_cb: call: item=0x20c2820, handler (0x20c0c10, 6)
<0x1927>    gpgme:keylist_colon_handler: call: ctx=0x20c0810, key = 0x20c2850, line = (null)
<0x1927>    gpgme:gpg_io_event: call: gpg=0x20c0c10, event 0x7fd8b1a20ad0, type 2, type_data 0x20c2850
<0x1927>      _gpgme_remove_io_cb: call: data=0x20c2800, setting fd 0x6 (item=0x20c2820) done
<0x1927>    gpgme:gpg_io_event: call: gpg=0x20c0c10, event 0x7fd8b1a20ad0, type 1, type_data 0x7fff5afd0700
<0x1927>  gpgme_op_keylist_next: leave: key=0x20c2850 (20CD3FF80DA6C1E46CD9F135CC73A8A60BF38589)
<0x1927>  gpgme_release: call: ctx=0x20c0810
<0x1927>  gpgme_new: enter: r_ctx=0x7fff5afd0818
<0x1927>  gpgme_new: leave: ctx=0x20c2210
<0x1927>  gpgme_op_keylist_start: enter: ctx=0x20c2210, pattern=4BE78BDCF3F5352CF624A6DF3AD6F8118300CC02, secret_only=0
<0x1927>    _gpgme_add_io_cb: call: ctx=0x20c2210, fd 4, dir=1 -> tag=0x20c1f50
<0x1927>    _gpgme_add_io_cb: call: ctx=0x20c2210, fd 6, dir=1 -> tag=0x20c1fa0
<0x1927>    gpgme:gpg_io_event: call: gpg=0x20c0c10, event 0x7fd8b1a20ad0, type 0, type_data (nil)
<0x1927>  gpgme_op_keylist_start: leave
<0x1927>  gpgme_op_keylist_next: enter: ctx=0x20c2210
<0x1927>    _gpgme_run_io_cb: call: item=0x20c1fc0, need to check
<0x1927>    _gpgme_run_io_cb: call: item=0x20c1fc0, handler (0x20c0c10, 6)
<0x1927>    gpgme:keylist_colon_handler: call: ctx=0x20c2210, key = (nil), line = tru::0:1433443869:2410285847:3:1:5
<0x1927>    gpgme:keylist_colon_handler: call: ctx=0x20c2210, key = (nil), line = pub:-:1024:17:3AD6F8118300CC02:1039074767:::-:::scESC::::::
<0x1927>    gpgme:keylist_colon_handler: call: ctx=0x20c2210, key = 0x20c2b70, line = fpr:::::::::4BE78BDCF3F5352CF624A6DF3AD6F8118300CC02:
<0x1927>    gpgme:keylist_colon_handler: call: ctx=0x20c2210, key = 0x20c2b70, line = uid:-::::1203999932::275AAD3E991F1962AD510CC96760907BE70FE668::Bla <bla@com>:
<0x1927>    gpgme:keylist_colon_handler: call: ctx=0x20c2210, key = 0x20c2b70, line = uid:-::::1203999938::59689891229F1817EF66BFC63D9D0BB2F45F5209::Bla <bla@com>:
<0x1927>    gpgme:keylist_colon_handler: call: ctx=0x20c2210, key = 0x20c2b70, line = uid:r::::::8A709552E7AB85B53DDAE18A48C0978E5EBF5547::Bla <bla@com>:
<0x1927>    gpgme:keylist_colon_handler: call: ctx=0x20c2210, key = 0x20c2b70, line = sub:-:2048:16:942E547C12A6B1C2:1039075030::::::e::::::
<0x1927>    gpgme:keylist_colon_handler: call: ctx=0x20c2210, key = 0x20c2b70, line = fpr:::::::::E69EF5226BBF7EC14F1D7D96942E547C12A6B1C2:
<0x1927>    _gpgme_run_io_cb: call: item=0x20c1f70, need to check
<0x1927>    _gpgme_run_io_cb: call: item=0x20c1f70, handler (0x20c0c10, 4)
<0x1927>      _gpgme_remove_io_cb: call: data=0x20c1f50, setting fd 0x4 (item=0x20c1f70) done
<0x1927>    _gpgme_run_io_cb: call: item=0x20c1fc0, need to check
<0x1927>    _gpgme_run_io_cb: call: item=0x20c1fc0, handler (0x20c0c10, 6)
<0x1927>    gpgme:keylist_colon_handler: call: ctx=0x20c2210, key = 0x20c2b70, line = (null)
<0x1927>    gpgme:gpg_io_event: call: gpg=0x20c0c10, event 0x7fd8b1a20ad0, type 2, type_data 0x20c2b70
<0x1927>      _gpgme_remove_io_cb: call: data=0x20c1fa0, setting fd 0x6 (item=0x20c1fc0) done
<0x1927>    gpgme:gpg_io_event: call: gpg=0x20c0c10, event 0x7fd8b1a20ad0, type 1, type_data 0x7fff5afd0760
<0x1927>  gpgme_op_keylist_next: leave: key=0x20c2b70 (4BE78BDCF3F5352CF624A6DF3AD6F8118300CC02)
<0x1927>  gpgme_release: call: ctx=0x20c2210
<0x1927>  gpgme_new: enter: r_ctx=0x7fff5afd07c8
<0x1927>  gpgme_new: leave: ctx=0x20c2550
<0x1927>  gpgme_set_passphrase_cb: call: ctx=0x20c2550, passphrase_cb=(nil)/(nil)
<0x1927>  gpgme_set_pinentry_mode: call: ctx=0x20c2550, pinentry_mode=4
<0x1927>  gpgme_set_passphrase_cb: call: ctx=0x20c2550, passphrase_cb=0x403420/0x20c0058
<0x1927>  gpgme_set_passphrase_cb: call: ctx=0x20c2550, passphrase_cb=0x403420/0x20c0058
<0x1927>  gpgme_new: enter: r_ctx=0x7fff5afd0768
<0x1927>  gpgme_new: leave: ctx=0x20c0810
<0x1927>  gpgme_op_keylist_start: enter: ctx=0x20c0810, pattern=0BF38589, secret_only=0
<0x1927>    _gpgme_add_io_cb: call: ctx=0x20c0810, fd 4, dir=1 -> tag=0x20c4fd0
<0x1927>    _gpgme_add_io_cb: call: ctx=0x20c0810, fd 6, dir=1 -> tag=0x20c5120
<0x1927>    gpgme:gpg_io_event: call: gpg=0x20c1d50, event 0x7fd8b1a20ad0, type 0, type_data (nil)
<0x1927>  gpgme_op_keylist_start: leave
<0x1927>  gpgme_op_keylist_next: enter: ctx=0x20c0810
<0x1927>    _gpgme_run_io_cb: call: item=0x20c5140, need to check
<0x1927>    _gpgme_run_io_cb: call: item=0x20c5140, handler (0x20c1d50, 6)
<0x1927>    gpgme:keylist_colon_handler: call: ctx=0x20c0810, key = (nil), line = tru::0:1433443869:2410285847:3:1:5
<0x1927>    gpgme:keylist_colon_handler: call: ctx=0x20c0810, key = (nil), line = pub:u:2048:1:CC73A8A60BF38589:1433443717:::u:::scESC:::::: 
<0x1927>    gpgme:keylist_colon_handler: call: ctx=0x20c0810, key = 0x20c5170, line = fpr:::::::::20CD3FF80DA6C1E46CD9F135CC73A8A60BF38589:  
<0x1927>    gpgme:keylist_colon_handler: call: ctx=0x20c0810, key = 0x20c5170, line = uid:u::::1433443717::9963CFDE0C8920AD077B06A281992C4008E67E4F::testkey3 (testkey3) <test@vanheusden.com>:
<0x1927>    gpgme:keylist_colon_handler: call: ctx=0x20c0810, key = 0x20c5170, line = sub:u:2048:1:22317805D48C1491:1433443717::::::e::::::
<0x1927>    gpgme:keylist_colon_handler: call: ctx=0x20c0810, key = 0x20c5170, line = fpr:::::::::FB6FFB7D8BEC710A745DE86C22317805D48C1491:
<0x1927>    _gpgme_run_io_cb: call: item=0x20c4ff0, need to check
<0x1927>    _gpgme_run_io_cb: call: item=0x20c4ff0, handler (0x20c1d50, 4)
<0x1927>      _gpgme_remove_io_cb: call: data=0x20c4fd0, setting fd 0x4 (item=0x20c4ff0) done
<0x1927>    _gpgme_run_io_cb: call: item=0x20c5140, need to check
<0x1927>    _gpgme_run_io_cb: call: item=0x20c5140, handler (0x20c1d50, 6)
<0x1927>    gpgme:keylist_colon_handler: call: ctx=0x20c0810, key = 0x20c5170, line = (null)
<0x1927>    gpgme:gpg_io_event: call: gpg=0x20c1d50, event 0x7fd8b1a20ad0, type 2, type_data 0x20c5170
<0x1927>      _gpgme_remove_io_cb: call: data=0x20c5120, setting fd 0x6 (item=0x20c5140) done
<0x1927>    gpgme:gpg_io_event: call: gpg=0x20c1d50, event 0x7fd8b1a20ad0, type 1, type_data 0x7fff5afd06c0
<0x1927>  gpgme_op_keylist_next: leave: key=0x20c5170 (20CD3FF80DA6C1E46CD9F135CC73A8A60BF38589)
<0x1927>  gpgme_release: call: ctx=0x20c0810
<0x1927>  gpgme_signers_clear: call: ctx=0x20c2550
<0x1927>  gpgme_signers_add: enter: ctx=0x20c2550, key=0x20c2850 (20CD3FF80DA6C1E46CD9F135CC73A8A60BF38589)
<0x1927>  gpgme_signers_add: leave
<0x1927>  gpgme_op_encrypt_sign: enter: ctx=0x20c2550, flags=0x1, plain=0x20c2ed0, cipher=0x20c3f20
<0x1927>  gpgme_op_encrypt_sign: check: ctx=0x20c2550, recipient[0] = 0x20c5170 (20CD3FF80DA6C1E46CD9F135CC73A8A60BF38589)
<0x1927>    gpgme_sig_notation_get: call: ctx=0x20c2550, ctx->sig_notations=(nil)
<0x1927>    _gpgme_add_io_cb: call: ctx=0x20c2550, fd 4, dir=1 -> tag=0x20c2070
<0x1927>    _gpgme_add_io_cb: call: ctx=0x20c2550, fd 8, dir=1 -> tag=0x20c21c0
<0x1927>    _gpgme_add_io_cb: call: ctx=0x20c2550, fd 11, dir=0 -> tag=0x20c2210
<0x1927>    gpgme:gpg_io_event: call: gpg=0x20c1d50, event 0x7fd8b1a20ad0, type 0, type_data (nil)
<0x1927>    _gpgme_run_io_cb: call: item=0x20c2230, need to check
<0x1927>    _gpgme_run_io_cb: call: item=0x20c2230, handler (0x20c2ed0, 11)
<0x1927>    _gpgme_data_outbound_handler: enter: dh=0x20c2ed0, fd=0xb
<0x1927>    _gpgme_data_outbound_handler: leave
<0x1927>    _gpgme_run_io_cb: call: item=0x20c2230, need to check
<0x1927>    _gpgme_run_io_cb: call: item=0x20c2230, handler (0x20c2ed0, 11)
<0x1927>    _gpgme_data_outbound_handler: enter: dh=0x20c2ed0, fd=0xb
<0x1927>        _gpgme_remove_io_cb: call: data=0x20c2210, setting fd 0xb (item=0x20c2230) done
<0x1927>    _gpgme_data_outbound_handler: leave
<0x1927>    _gpgme_run_io_cb: call: item=0x20c2090, need to check
<0x1927>    _gpgme_run_io_cb: call: item=0x20c2090, handler (0x20c1d50, 4)
<0x1927>    _gpgme_run_io_cb: call: item=0x20c2090, need to check
<0x1927>    _gpgme_run_io_cb: call: item=0x20c2090, handler (0x20c1d50, 4)
<0x1927>    _gpgme_cancel_with_err: enter: ctx=0x20c2550, ctx_err=117440566, op_err=0
<0x1927>        _gpgme_remove_io_cb: call: data=0x20c2070, setting fd 0x4 (item=0x20c2090) done
<0x1927>        _gpgme_remove_io_cb: call: data=0x20c21c0, setting fd 0x8 (item=0x20c21e0) done
<0x1927>      gpgme:gpg_io_event: call: gpg=0x20c1d50, event 0x7fd8b1a20ad0, type 1, type_data 0x7fff5afd06c0
<0x1927>    _gpgme_cancel_with_err: leave
<0x1927>  gpgme_op_encrypt_sign: error: Unusable secret key <GPGME>
<0x1927>  gpgme_release: call: ctx=0x20c2550

编辑

根据@kylehuff的要求,这是选择密钥的代码:

search_key_result_t gpgme::find_key(const std::string & key_id, const bool priv_key_only, gpgme_key_t *k, std::string *const error)
  {
          error -> clear();

          *k = NULL;

          gpgme_ctx_t ctx = NULL;
          if (!my_gpgme_new(&ctx, false, error))
                  return SK_ERROR;

          gpgme_error_t err = gpgme_op_keylist_start(ctx, key_id.c_str(), priv_key_only ? 1 : 0);
          if (err != GPG_ERR_NO_ERROR)
          {
                  error -> append(format("Problem searching for %s: %s (%d)", key_id.c_str(), gpg_strerror(err), err));
                  gpgme_release(ctx);
                  return SK_ERROR;
          }

          err = gpgme_op_keylist_next(ctx, k);
          if (err == GPG_ERR_EOF)
                  return SK_NOT_FOUND;

          if (err != GPG_ERR_NO_ERROR)
          {
                  error -> append(format("Problem finding %s: %s (%d)", key_id.c_str(), gpg_strerror(err), err));
                  gpgme_release(ctx);
                  return SK_ERROR;
          }

          gpgme_release(ctx);

          return SK_FOUND;
  }

然后在构造函数中我这样做:

std::string error;
  if (find_key(my_key_id, true, &my_key, &error) != SK_FOUND)
          error_exit(false, "Cannot find key %s: %s", my_key_id.c_str(), error.c_str());

当签署时间到来时:

          if (find_key(target_uid, false, &recipient[0], error) != SK_FOUND)
                  break;

          gpgme_signers_clear(ctx);
          err = gpgme_signers_add(ctx, my_key);
          if (err != GPG_ERR_NO_ERROR)
          {
                  error -> append(format("gpgme_signers_add(%s) failed: %s (%d)", my_key_id.c_str(), gpg_strerror(err), err));
                  break;
          }

          int n_signers = gpgme_signers_count(ctx);
          if (n_signers != 1)
          {
                  error -> append(format("Number of signers (%d) not expected number (1)", n_signers));
                  break;
          }

          err = gpgme_op_encrypt_sign(ctx, recipient, GPGME_ENCRYPT_ALWAYS_TRUST /* FIXME */, data_in, sig);
          if (err != GPG_ERR_NO_ERROR)
          {
                  error -> append(format("gpgme_op_encrypt failed: %s (%d)", gpg_strerror(err), err));
                  break;
          }

@kylehuff,这是你要求的内容吗?感谢。

编辑

以下是20CD3FF80DA6C1E46CD9F135CC73A8A60BF38589的清单:

tru::0:1433443869:2410285847:3:1:5
pub:u:2048:1:CC73A8A60BF38589:2015-06-04:::u:testkey3 (testkey3) <test@vanheusden.com>::scESC:
sub:u:2048:1:22317805D48C1491:2015-06-04::::::e:

编辑

folkert@travelmate:~$ gpg2 --local-user 14B7E8E6 --sign bla.txt

folkert@travelmate:~$ gpg --verify bla.txt.gpg gpg: 使用RSA密钥ID 74D6F5C6于2015年6月18日晚上07:18:17 UTC签名 gpg: 来自“testkey2 (testkey2) ”的好签名

通过编辑密钥,我可以看到74d6f5c6确实是签名子密钥:

sub 1024R/74D6F5C6 创建于2015-05-31 到期时间:从不 用途:S

所以我有点惊讶为什么这对gpgme不起作用。 直接使用gpgme_get_key()也会出现同样的错误。


你能发布 gpgme_signers_add 方法和密钥选择的实际代码吗?在你提供的调试输出中,所选密钥与问题顶部列出的任何密钥都不匹配。操作 gpgme_signers_add 正在使用密钥“20CD3FF80DA6C1E46CD9F135CC73A8A60BF38589”,这是你拥有公共和私有部分但未列出的密钥吗? - kylehuff
请问您能具体说明您正在添加哪个密钥吗?它可能是仅签名或仅加密吗?您是选择私钥还是其中一个子密钥? - Nickolay Olshevsky
@NickolayOlshevsky 我正在使用顶部列出的密钥:14B7E8E6 - Folkert van Heusden
@kylehuff:0BF38589也在密钥环中,但没有被选中。在调用gpgme_signers_add之前,我调用了pgme_key_get_string_attr(my_key, GPGME_ATTR_KEYID),这清楚地显示14B7E8E6被选中。 - Folkert van Heusden
1个回答

2
很难确定发生了什么事情,即使有样本,但有几种可能的情况—— my_gpgme_new(&ctx, false, error) 方法中的某些操作可能是不可预测的。这个函数到底在做什么?为什么不使用标准的 gpgme_new 方法?
在提供的示例中,您正在使用函数 search_key_result_t gpgme::find_key();是否需要多个签名者?如果需要,至少在测试时,为什么不简化并只使用 gpgme_get_key()?即:
  gpgme_error_t err;
  gpgme_key_t key;

  err = gpgme_get_key (ctx, key_string, &key, 1);
  if (err) {
    // .. error handling
  }
  gpgme_signers_clear();
  err = gpgme_signers_add (ctx, key);
  gpgme_key_unref (key);

  int n_signers = gpgme_signers_count(ctx);
  if (n_signers != 1) {
    // .. error handling
  }

  err = gpgme_op_encrypt_sign(ctx, recipient, ....);

此方法似乎是将该方法添加到 gpgme 命名空间中。您是否可能还覆盖了 gpgme 命名空间中的内置方法?
至于接收方对象,它是如何构建的?它应该是一个以 null 结尾的 gpgme_key_t 结构,即使它只有一个接收者。即:
  gpgme_key_t recipients[2] = { NULL, NULL };
  err = gpgme_get_key (ctx, recipient_fpr.c_str(), &recipients[0], 0);
  if (err) { // .. error handling }

如果收件人以数组形式提供:

  gpgme_key_t recipients = new gpgme_key_t[recip_array.size()];
  err = gpgme_get_key (ctx, recipient_fpr.c_str(), &recipients[0], 0);
  if (err) { // .. error handling }
  recipients[recip_array.size()] = NULL; // null terminate the array

my_gpgme_new 是 gpgme_new 的包装器,它调用了 gpgme_new,如果适用的话还会调用 gpgme_set_pinentry_mode 和 gpgme_set_passphrase_cb。关于 find_key:该方法通过任何 gpgme 理解的搜索查询来搜索密钥。希望这使人们能够按密钥 ID 或电子邮件地址进行搜索。命名空间:my_gpgme_new 和 find_key 是我的 gpgme 类的一部分,因此它们不应与 gpgme 库发生冲突(据我所知,该库是纯 c)。 - Folkert van Heusden
对于接收对象:它确实是一个由2个元素组成的数组,最后一个元素为NULL。为了帮助你们帮助我,我已经将代码上传到http://vps001.vanheusden.com/~folkert/gpgme.cpp和http://vps001.vanheusden.com/~folkert/gpgme.h。 最终将会开源。 - Folkert van Heusden
好的,看到实际情况应该会有所帮助,即使没有别的,也能防止我猜测。为了完整起见,您能否提供gpg --with-colons --list-keys 20CD3FF80DA6C1E46CD9F135CC73A8A60BF38589的输出? - kylehuff
我会将其添加到原始帖子中。 - Folkert van Heusden
您在评论中提到方法gpgme_signers_add选择了密钥14B7E8E6,但这并未显示为您修改问题后的输出的一部分。 它应该使用主要子密钥,这是唯一列出的“签名”能力子密钥。 短ID为14B7E8E6的子密钥在哪里? 它是否过期了?(我曾经看到gpg未使用--list-keys显示过期的子密钥)。 您能否使用此密钥从cli签名?例如:gpg --local-user 0BF38589 -asr 0BF38589 - kylehuff
我在问题下面添加了一条评论,附带了这些命令的结果。无论如何,我还是会给你那250分的奖励,感谢你的努力! - Folkert van Heusden

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接