PHP gnupg 签名验证的返回值是什么意思?

What do returned values of PHP gnupg signature verification mean?

我想验证 PHP 中的 pgp 签名文本。根据 PHP 文档和对 this 问题的回答,我制作了简单的脚本来测试 gnupg 库。我使用带有 Enigmail 的 Thunderbird 在两个电子邮件帐户之间发送了签名电子邮件 - 接收 Thunderbird 显示签名正确。

在 PHP 中,当我使用纯电子邮件文本和发件人 public 键时,verify() 函数 returns 数组如下:

array(1) {
  [0]=>
  array(5) {
    ["fingerprint"]=>
    string(40) "468F82339FC55DE5CAFD71BB63DD32AE1308A57F"
    ["validity"]=>
    int(0)
    ["timestamp"]=>
    int(1443033896)
    ["status"]=>
    int(0)
    ["summary"]=>
    int(0)
  }
}

当我更改签名消息中的单个单词时,结果更改为:

array(1) {
  [0]=>
  array(5) {
    ["fingerprint"]=>
    string(16) "63DD32AE1308A57F"
    ["validity"]=>
    int(0)
    ["timestamp"]=>
    int(0)
    ["status"]=>
    int(117440520)
    ["summary"]=>
    int(4)
  }
}

最后,当我更改大量文本或破坏签名时,函数 returns false.

那么,这些数组值是什么意思?

如果我只想简单地识别文本是否正确签名,我可以将返回的 fingerprint 与 public 密钥的指纹进行比较,并检查状态和摘要是否等于 0?

PHP 的 GnuPG 文档确实缺少此处的信息。查看source code和GPGME的手册和来源,可以推导出相关信息。

免责声明: 答案包含一些猜测,请务必对在其上构建时发生的情况有一个合理的感觉,并随时提供反馈!

有效期

Why validity is always 0?

为了验证签名的 validity,您需要分配信任(因此 GnuPG 能够计算信任链)。 validity is defined in following GPGME enums:

/* The available validities for a trust item or key.  */
typedef enum
  {
    GPGME_VALIDITY_UNKNOWN   = 0,
    GPGME_VALIDITY_UNDEFINED = 1,
    GPGME_VALIDITY_NEVER     = 2,
    GPGME_VALIDITY_MARGINAL  = 3,
    GPGME_VALIDITY_FULL      = 4,
    GPGME_VALIDITY_ULTIMATE  = 5
  }
gpgme_validity_t;

时间戳

timestamp value is a timestamp of what? Time when message was signed?

是的,这个很简单,这是签名创建时间戳。请注意,时间戳通常由签名者定义,可以伪造为任意日期。

状态

Same with summary what stands value of 4 for?

正在阅读documentation (gpgme_error_t status), it seems the status is defined in gpg-error.h. This is a very long list hosted in GnuPG's git repository

然而,你问题中定义的状态对我来说没有意义。

总结

Why status value is so big in second case? Its just random value or specific error code?

这是对签名的总结。同样,summary is defined in a GPGME enum:

/* Flags used for the SUMMARY field in a gpgme_signature_t.  */
typedef enum
  {
    GPGME_SIGSUM_VALID       = 0x0001,  /* The signature is fully valid.  */
    GPGME_SIGSUM_GREEN       = 0x0002,  /* The signature is good.  */
    GPGME_SIGSUM_RED         = 0x0004,  /* The signature is bad.  */
    GPGME_SIGSUM_KEY_REVOKED = 0x0010,  /* One key has been revoked.  */
    GPGME_SIGSUM_KEY_EXPIRED = 0x0020,  /* One key has expired.  */
    GPGME_SIGSUM_SIG_EXPIRED = 0x0040,  /* The signature has expired.  */
    GPGME_SIGSUM_KEY_MISSING = 0x0080,  /* Can't verify: key missing.  */
    GPGME_SIGSUM_CRL_MISSING = 0x0100,  /* CRL not available.  */
    GPGME_SIGSUM_CRL_TOO_OLD = 0x0200,  /* Available CRL is too old.  */
    GPGME_SIGSUM_BAD_POLICY  = 0x0400,  /* A policy was not met.  */
    GPGME_SIGSUM_SYS_ERROR   = 0x0800   /* A system error occured.  */
  }
gpgme_sigsum_t;

因此,您必须将结果读取为二进制标志。状态 4 表示签名错误。

总结

第一个签名是几天前在 2015-09-23T18:44:56+00:00 由密钥 468F82339FC55DE5CAFD71BB63DD32AE1308A57F 生成的,是正确的签名,但可以验证密钥(缺少信任路径).

第二个签名似乎是由同一个密钥签发的,但已损坏。

If i want to just simply recognize if text is signed correctly or not, can i just compare returned fingerprint with fingerprint of public key and check if status and summary are equal to 0?

据我所知,您应该测试一下 summary 的第 4 位是否已设置。如果已设置,则您的签名不好。不要和4比较,而是用位操作来测试单个位:

($summary & 0x04) == 0x04

如果您不使用信任网和 validity 标志来验证签名,请确保将整个指纹与受信任密钥列表进行比较。