我想在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
?
答案 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
标记来验证签名,请确保将整个指纹与可信密钥列表进行比较。