使用OpenSSL进行数字签名验证

时间:2010-01-04 11:56:03

标签: ruby openssl

如何在Ruby中使用OpenSSL验证CMS / PKCS#7消息?
PKCS#7消息用作用户消息的数字签名,因此我需要签署新的用户消息并验证传入的消息。 我在documentation和谷歌中找不到任何有用的内容。 我发现很少有用于签名的代码示例,但没有用于验证:

signed = OpenSSL::PKCS7::sign(crt, key, data, [], OpenSSL::PKCS7::DETACHED)

1 个答案:

答案 0 :(得分:39)

简短回答

假设所有内容都定义为它们在您的代码段中,具有分离的签名,没有证书链到受信任的根,证书crt,签名signed和数据data,以下应该做你想做的事:

store = OpenSSL::X509::Store.new
p7 = OpenSSL::PKCS7.new(signed.to_der)
verified = p7.verify([crt], store, data, 
                     OpenSSL::PKCS7::DETACHED || OpenSSL::PKCS7::NOVERIFY)

(我没有测试过,YMMV)

全文

以下是我如何找到这一点的完整故事,其中包含我所使用的所有来源的链接,因此如果您需要更多信息,您可以在某处查看。

看一下OpenSSL :: PKCS7文档,我们找到this morsel of wisdom

  

PKCS7.new => PKCS7
   PKCS7.new(string)=> PKCS7
  此类中的许多方法都没有记录。

快速谷歌也不会改变任何事情。这表明我们将不得不采取更极端的措施。让我们为使用OpenSSL :: PKCS7验证签名的任何人做Google code search

嗯。我们找到some test cases。非常好;至少它有单元测试,可以帮助显示功能确实有效,并提供它的工作原理演示。

store = OpenSSL::X509::Store.new
store.add_cert(@ca_cert)
ca_certs = [@ca_cert]

data = "aaaaa\r\nbbbbb\r\nccccc\r\n"
tmp = OpenSSL::PKCS7.sign(@ee1_cert, @rsa1024, data, ca_certs)
p7 = OpenSSL::PKCS7::PKCS7.new(tmp.to_der)
certs = p7.certificates
signers = p7.signers
assert(p7.verify([], store))
assert_equal(data, p7.data)

那还不错。包装证书商店。对您的数据进行签名,然后从签名数据中创建一个新的OpenSSL :: PKCS7对象。然后,您可以在其上调用certificates以提取其签名的证书链,signers以提取签名者,并且可以调用verify来验证签名是否有效。您似乎将包含可信CA证书的证书存储作为要验证的第二个参数传递。您可以通过调用data来提取数据。

但第一个论点意味着什么?在我们的测试用例中似乎没有人传递任何东西,只有第一个参数的空列表。嗯。一个谜。我们将回过头来看。

verify的第三个可选参数看起来像用于verifying a detached signature

data = "aaaaa\nbbbbb\nccccc\n"
flag = OpenSSL::PKCS7::BINARY|OpenSSL::PKCS7::DETACHED
tmp = OpenSSL::PKCS7.sign(@ee1_cert, @rsa1024, data, ca_certs, flag)
p7 = OpenSSL::PKCS7::PKCS7.new(tmp.to_der)
a1 = OpenSSL::ASN1.decode(p7)

certs = p7.certificates
signers = p7.signers
assert(!p7.verify([], store))
assert(p7.verify([], store, data))

回到第一个参数。当我们进行代码搜索时,我们发现的不仅仅是测试用例;我们还发现了一些其他用途。事实上,第二个似乎是use the first argument

# 'true' if signature was created using given cert, 'false' otherwise
def match?(cert)
  @p7.verify([cert.raw_cert], @store, nil, OpenSSL::PKCS7::NOVERIFY)
end

啊,好的。这是要检查的证书列表。现在有第四个参数,它似乎由标志组成。检查OpenSSL docs,我们看到这个不直观的名称(使用NOVERIFY标志验证?)意味着您应该只检查传入的证书和签名中嵌入的证书的签名,而不是尝试验证整个针对您信任的CA商店的证书链。

这是所有有用的信息,但有什么我们遗漏的吗?值得庆幸的是,Ruby是开源软件,因此我们可以“使用源代码,Luke!”在谷歌代码搜索上乱七八糟之后,我们找到了definition of ossl_pkcs7_verify。一旦你超越了有些神秘的名字,代码就可以直接阅读;它基本上只是将其参数转换为OpenSSL可以理解的格式,并调用:

ok = PKCS7_verify(p7, x509s, x509st, in, out, flg);

所以,它看起来像that',我们真的想要寻找文档。

说明

PKCS7_verify()验证PKCS#7 signedData结构。 p7 是要验证的PKCS7结构。 证书是一组用于搜索签名者证书的证书。 商店是受信任的证书商店(用于链验证)。如果内容不在 p7 中(即已分离),则 indata 是已签名的数据。内容将写入 out 如果它不是NULL。

flags 是一组可选标志,可用于修改验证 操作。

PKCS7_get0_signers() p7 检索签名者的证书,确实如此 检查其有效性或是否有任何签名有效。 证书标志参数与PKCS7_verify().中的含义相同

有关详细信息,请参阅full man page

哦,作为旁注,我在搜索时找到了this warning;它看起来像在Ruby 1.9中,并且可能在一些更高版本的Ruby 1.8中,该类已从冗余的OpenSSL :: PKCS7 :: PKCS7转移到OpenSSL :: PKCS7。

warn("Warning: OpenSSL::PKCS7::PKCS7 is deprecated after Ruby 1.9; use OpenSSL::PKCS7 instead")