使用OpenSSL进行数字签名validation

如何在Ruby中使用OpenSSLvalidationCMS / PKCS#7消息?
PKCS#7消息用作用户消息的数字签名,因此我需要签署新的用户消息并validation传入的消息。 我没有在文档和谷歌中找到任何有用的东西。 我发现很少有用于签名的代码示例,但没有用于validation:

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

简短的回答

假设所有内容都定义为它们在您的代码段中,具有分离的签名,没有证书链到受信任的根,证书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文档,我们发现了这一点 :

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

一个快速的谷歌也没有改变任何东西。 这说明我们将不得不采取更极端的措施。 让我们为使用OpenSSL :: PKCS7validation签名的任何人进行Google代码搜索 。

嗯。 我们找到了一些测试用例 。 非常好; 至少它有unit testing,可以帮助显示function确实有效,并提供它的工作原理演示。

 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提取签名者,并且可以调用validation以validation签名是否有效。 您似乎通过包含可信CA证书的证书存储区作为要validation的第二个参数。 您可以通过调用data来提取数据。

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

verify的第三个可选参数看起来像是用于validation分离的签名 :

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

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

 # '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文档 ,我们看到这个不直观的名称(使用NOVERIFY标志validation?)意味着您应该只检查传入的证书和签名中嵌入的证书的签名,而不是尝试validation整个证书链您信任的CA商店。

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

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

所以,看起来这就是我们真正想要寻找文档的地方。

描述

PKCS7_verify()validationPKCS#7 signedData结构。 p7是要validation的PKCS7结构。 certs是一组用于搜索签名者证书的证书。 store是一个值得信赖的certficate商店(用于链validation)。 indata是签名数据,如果内容不存在于p7中 (即它已被分离)。 如果内容不为NULL,则写入内容。

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

PKCS7_get0_signers()p7检索签名者的证书,它不检查其有效性或任何签名是否有效。 certsflags参数与PKCS7_verify().具有相同的含义PKCS7_verify().

有关详细信息,请参阅完整的手册页 。

哦,作为旁注,我在搜索时发现了这个警告 ; 它看起来像在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")