我公司有一个网络文档管理应用程序,我被指派找到一种用用户数字证书签署pdf文件的方法。
pdf可以从几kb到100Mb以上,这是通过互联网进行的,因此签名 必须 在网络服务器上进行。
为了做到这一点,我构建了一个activeX控件,要求用户选择证书,然后使用WebClient.UploadData将证书作为字节数组发送到网页上。
在我尝试签署pdf文档的网页上,我收到错误“密钥不存在”。这对我来说并不奇怪,因为当我在选择合适的证书后直接通过https连接使用证书时,我会提示输入密钥。 activeX不会发生这种情况。
这就是我从用户那里获得证书的方式:
private static X509Certificate2 PickCertificate()
{
X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
try
{
store.Open(OpenFlags.ReadOnly);
// pick a certificate from the store
X509Certificate2 cert = X509Certificate2UI.SelectFromCollection(store.Certificates, "Title", "Message", X509SelectionFlag.SingleSelection)[0];
// show certificate details dialog
X509Certificate2UI.DisplayCertificate(cert);
store.Close();
return cert;
}
finally { store.Close(); }
}
如何让用户提供我错过的钥匙?
答案 0 :(得分:4)
您希望用户将其证书的私钥上传到网络服务器,以便签署PDF吗?如果是这样,从安全角度来看,这基本上已被打破。
我想你可能已经错过了公共证书!=私钥。 (我们大多数人都很草率,并使用“证书”这个词来指代那些事情中的任何一个(或两个),所以这并不完全令人惊讶)。从内存开始,CryptoAPI只有一组选择的方法,允许您访问密钥。其中必须有一个“导出为PFX”的方法,所以如果你真的想要的话,你可以让你的设计工作,但是我没办法推荐这个。 (将私钥发送到网络服务器的风险,破坏的不可否认性等等)。
如果你真的必须在服务器上签名[我真的不明白你的论点,签名不应该为上传添加太多数据],那么你应该考虑一个多层架构和一个密钥托管机制。这样你至少可以减少一些安全问题(但你仍然会失去不可否认性......并引入其他风险。这里没有免费午餐。)
所以......您可能需要考虑重新设计应用程序,以便在上载PDF文件之前在客户端(在ActiveX控件中)发生PDF签名。我想你需要一个第三方库来进行签名步骤,如this SO thread中所述。