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

时间:2015-09-25 16:47:35

标签: php gnupg pgp

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

在PHP中,当我使用普通电子邮件文本和发件人公钥时,verify()函数返回如下数组:

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)
  }
}

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

那么,这些数组值意味着什么?

  • 为什么validity总是0
  • timestamp值是什么时间戳?消息签署的时间?
  • 为什么status值在第二种情况下如此之大?它只是随机值或特定错误代码?
  • summary相同,4的价值是什么?

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

1 个答案:

答案 0 :(得分:2)

PHP的GnuPG文档确实缺少这里的信息。查看source code和GPGME手册和来源,您可以获得相关信息。

免责声明:答案包含一些猜测,一定要对构建它的内容有一个合理的感觉,并随时提供反馈!

有效期

  

为什么有效性始终为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;

时间戳

  

时间戳值是什么时间戳?消息签署的时间?

是的,这个很容易,这是签名创建时间戳。请注意,时间戳通常由签名者定义,并且可以伪造到任意日期。

状态

  

与摘要相同的是4的值是什么?

阅读documentation (gpgme_error_t status),似乎状态在gpg-error.h中定义。这是very long list hosted in GnuPG's git repository

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

摘要

  

为什么在第二种情况下状态值如此之大?它只是随机值或特定错误代码?

这是签名的摘要。同样,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生成的,并且是正确的签名,但密钥可以被验证(缺少信任路径)。

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

  

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

据我了解发生了什么,你应该测试是否设置了summary的第4位。如果设置好了,你的签名就会很糟糕。不要将它与4进行比较,而是使用位操作来测试单个位:

($summary & 0x04) == 0x04

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