我们编写了一个文档管理系统,并希望使用Web客户端对文档进行数字签名。我们的Java客户端应用程序已经能够应用和检查数字签名,但我们希望甚至可以使用我们的Web客户端进行签名。这是用GWT编写的,因此,当在客户端运行时,它是一个JavaScript应用程序。
我们不想创建Java applet并在客户端上下载并执行它。我们希望使用浏览器安全设备或浏览器API来签署文档。我们还希望保留整个文档服务器端,并仅将文档哈希移动到客户端。
我们认为应该可以使用 NSS 或 npapi / npruntime ,但我们没有找到任何相关信息。 (顺便说一下,IE也可以使用npruntime吗?我们应该使用ActiveX来实现与IE相同的结果吗?)
你有任何提示吗?
答案 0 :(得分:9)
经过一些谷歌搜索后,我找到了答案。 Mozilla通过window.crypto对象导出其NSS模块的一部分。执行此类操作的更标准方法可能是DOMCrypt,目前是discusses in W3C。 谷歌Chrome开发人员将等待W3C标准化DOMCrypt,而微软则需要使用ActiveX对象as explained here(即使在Windows上使用Firefox / Chrome / Opera也是如此)。
答案 1 :(得分:4)
目前(2016年5月)不可能。
Chrome已经放弃了Java支持。 'Windows边缘'不会有。 IE11的支持很糟糕,Oracle决定停止使用java插件。它只适用于Firefox,旧版本的IE和Java插件。
新的WebCryptographyApi标准为浏览器提供数字签名支持,但它没有支持#11支持
解决此问题的真实电子政务解决方案: 1)在用户的PC上安装本地Java应用程序。应用程序侦听端口,例如5678 2)在您的页面中,javascript检测是否支持applet 3)如果没有支持,请以http://127.0.01:5678/sign形式连接到应用程序并将数据发送到签名。 4)应用程序是本地的,使用操作系统密钥库时没有问题,操作系统密钥库包括驱动程序PKCS#11。进行数字签名并准备结果 5)页面javascript定期查询结果并在准备好后检索它
答案 2 :(得分:0)
在Win / IE中,您仍然可以使用CAPICOM http://en.wikipedia.org/wiki/CAPICOM而无需任何第三方ActiveX或外部库。
这适用于安装IE的任何地方。
然而,这已经退休了。
以下是我用于登录IE的内容。我用例如:var signature = signDigest(stringToBeSigned);
function signDigest(text) {
if (window.event)
window.event.cancelBubble = true;
var dest = sign(text); //TODO
return dest;
}
// CAPICOM constants
var CAPICOM_STORE_OPEN_READ_ONLY = 0;
var CAPICOM_CURRENT_USER_STORE = 2;
var CAPICOM_CERTIFICATE_FIND_SHA1_HASH = 0;
var CAPICOM_CERTIFICATE_FIND_EXTENDED_PROPERTY = 6;
var CAPICOM_CERTIFICATE_FIND_TIME_VALID = 9;
var CAPICOM_CERTIFICATE_FIND_KEY_USAGE = 12;
var CAPICOM_DIGITAL_SIGNATURE_KEY_USAGE = 0x00000080;
var CAPICOM_AUTHENTICATED_ATTRIBUTE_SIGNING_TIME = 0;
var CAPICOM_INFO_SUBJECT_SIMPLE_NAME = 0;
var CAPICOM_ENCODE_BASE64 = 0;
var CAPICOM_E_CANCELLED = -2138568446;
var CERT_KEY_SPEC_PROP_ID = 6;
function IsCAPICOMInstalled() {
if (typeof (oCAPICOM) == "object") {
if ((oCAPICOM.object != null)) {
// We found CAPICOM!
return true;
}
}
}
function FindCertificateByHash() {
try {
// instantiate the CAPICOM objects
var MyStore = new ActiveXObject("CAPICOM.Store");
// open the current users personal certificate store
MyStore.Open(CAPICOM_CURRENT_USER_STORE, "My", CAPICOM_STORE_OPEN_READ_ONLY);
// find all of the certificates that have the specified hash
var FilteredCertificates = MyStore.Certificates.Find(CAPICOM_CERTIFICATE_FIND_SHA1_HASH, strUserCertigicateThumbprint);
var Signer = new ActiveXObject("CAPICOM.Signer");
Signer.Certificate = FilteredCertificates.Item(1);
return Signer;
// Clean Up
MyStore = null;
FilteredCertificates = null;
}
catch (e) {
if (e.number != CAPICOM_E_CANCELLED) {
return new ActiveXObject("CAPICOM.Signer");
}
}
}
function sign(src) {
if (window.crypto && window.crypto.signText)
return sign_NS(src);
else
return sign_IE(src);
}
function sign_NS(src) {
var s = crypto.signText(src, "ask");
return s;
}
function sign_IE(src) {
try {
// instantiate the CAPICOM objects
var SignedData = new ActiveXObject("CAPICOM.SignedData");
var TimeAttribute = new ActiveXObject("CAPICOM.Attribute");
// Set the data that we want to sign
SignedData.Content = src;
var Signer = FindCertificateByHash();
// Set the time in which we are applying the signature
var Today = new Date();
TimeAttribute.Name = CAPICOM_AUTHENTICATED_ATTRIBUTE_SIGNING_TIME;
TimeAttribute.Value = Today.getVarDate();
Today = null;
Signer.AuthenticatedAttributes.Add(TimeAttribute);
// Do the Sign operation
var szSignature = SignedData.Sign(Signer, true, CAPICOM_ENCODE_BASE64);
return szSignature;
}
catch (e) {
if (e.number != CAPICOM_E_CANCELLED) {
alert("An error occurred when attempting to sign the content, the error was: " + e.description);
}
}
return "";
}
我遇到了编码等问题,所以我也包含了我的控制器(.net)
byte[] decbuff = Convert.FromBase64String(signature);
//CAPICOM USES 16 BIT ENCODING
Encoding utf16Enc = Encoding.GetEncoding("UTF-16LE");
byte[] utf16Data = utf16Enc.GetBytes(getContent);
ContentInfo content = new ContentInfo(utf16Data);
System.Security.Cryptography.Pkcs.SignedCms cms = new System.Security.Cryptography.Pkcs.SignedCms(content,true);
cms.Decode(decbuff);
int length = decbuff.Length;
X509Certificate2 cert = cms.SignerInfos[0].Certificate;
X509Chain chain = new X509Chain();
bool theVal = chain.Build(cert);
cms.CheckHash();
cms.CheckSignature(false);
答案 3 :(得分:0)
我参与的一个项目使用Chrome和Native Messaging执行此操作:
https://github.com/CACBridge/ChromeCAC
这需要安装chrome插件,否则效果很好。适用于例如Intranet / Group环境,您知道需要提前完成此操作。
答案 4 :(得分:-1)
现在你可以做到。基于PKCS#11智能卡或令牌的Web应用程序可以使用Silverlight版本的NCryptoki实现。见http://www.ncryptoki.com
你有两个椅子:
1)使用Silverlight版本的NCryptoki并开发自己的Silverlight用户控件,使用智能卡提供的PKCS#11功能实现您的逻辑,在您的情况下使用数字签名
2)使用基于上述Silverlight版本的JQuery插件,并通过在JavaScript中调用PKCS#11函数在JavaScript中实现您的应用程序
此外,您可以使用Silverlight版本的NDigitSign(再次参见http://www.ncryptoki.com),它可以满足您的所有需求,并且可以在任何Web浏览器中实现。