我正在尝试使用javascript在客户端为PKCS#10 certifacate请求创建签名的PKCS#7消息。
PKCS#10有很好的例子:http://blogs.msdn.com/b/alejacma/archive/2009/01/28/how-to-create-a-certificate-request-with-certenroll-javascript.aspx
但我需要创建PKCS#7并且无法弄清楚如何做到这一点。 CertEnroll官方文档中缺少示例(实际上根本没有):http://msdn.microsoft.com/en-us/library/windows/desktop/aa374850(v=vs.85).aspx
我最终得到了这段代码:
var XCN_CRYPT_STRING_BASE64REQUESTHEADER = 3;
var XCN_CERT_NAME_STR_NONE = 0;
var _certEnrollClassFactory = new ActiveXObject("X509Enrollment.CX509EnrollmentWebClassFactory");
ComposePKCS10Request: function (containerName, subject)
{
// PKCS #10 certificate request
var objRequest = _certEnrollClassFactory.CreateObject("X509Enrollment.CX509CertificateRequestPkcs10");
var objCSP = objCertEnrollClassFactory.CreateObject("X509Enrollment.CCspInformation");
var objCSPs = objCertEnrollClassFactory.CreateObject("X509Enrollment.CCspInformations");
// Initialize the csp object using the desired Cryptograhic Service Provider (CSP)
objCSP.InitializeFromName("Microsoft Enhanced Cryptographic Provider v1.0");
// Add this CSP object to the CSP collection object
objCSPs.Add(objCSP);
// asymmetric private key that can be used for encryption, signing, and key agreement.
var objPrivateKey = _certEnrollClassFactory.CreateObject("X509Enrollment.CX509PrivateKey");
// Provide key container name, key length and key spec to the private key object
objPrivateKey.ContainerName = containerName;
//objPrivateKey.Length = 1024;
objPrivateKey.KeySpec = 1; // AT_KEYEXCHANGE = 1
// Provide the CSP collection object (in this case containing only 1 CSP object)
// to the private key object
objPrivateKey.CspInformations = objCSPs;
// Initialize P10 based on private key
objRequest.InitializeFromPrivateKey(1, objPrivateKey, ""); // context user = 1
// X.500 distinguished name (DN)
// The DN consists of a sequence of relative distinguished names (RDNs). Each RDN consists of a set of attributes,
// and each attribute consists of an object identifier (OID) and a value. The data type of the value is identified
// by the DirectoryString structure.
var objDn = _certEnrollClassFactory.CreateObject("X509Enrollment.CX500DistinguishedName");
// DN related stuff
objDn.Encode(subject, XCN_CERT_NAME_STR_NONE);
objRequest.Subject = objDn;
return objRequest;
}
CreatePKCS7: function (containerName, subject)
{
// PKCS #7 certificate request
var objPKCS7Request = _certEnrollClassFactory.CreateObject("X509Enrollment.CX509CertificateRequestPkcs7");
// initialize PKCS #7 certificate request by PKCS #10 certificate request
objPKCS7Request.InitializeFromInnerRequest(this.ComposePKCS10Request(containerName, subject));
var objSignerCert = _certEnrollClassFactory.CreateObject("X509Enrollment.CSignerCertificate");
var verifyType = 4; /* VerifyAllowUI, see typedef enum X509PrivateKeyVerify */
var encodingType = 0x3; /* see typedef enum EncodingType */
/**********************************************************************/
/* I have to provide certificate here??? How can I obtain it from UI? */
/**********************************************************************/
var strCertificate = '?????????????????????';
objSignerCert.Initialize(false, verifyType, encodingType, strCertificate);
/*****************************************************************************/
/* Also I'm not shure that SignerCertificate can be accessed via javascript. */
/*****************************************************************************/
objPKCS7Request.SignerCertificate = objSignerCert;
// represents the top level object and enables you to enroll in a certificate hierarchy and install a certificate response
var objEnroll = _certEnrollClassFactory.CreateObject("X509Enrollment.CX509Enrollment");
// Enroll
objEnroll.InitializeFromRequest(objPKCS7Request);
var pkcs7;
try
{
pkcs7 = objEnroll.CreateRequest(XCN_CRYPT_STRING_BASE64REQUESTHEADER);
}
catch (e)
{
...
}
return pkcs7;
}
有没有办法用javascript创建PKCS#7消息?
更新:我已经有了PKCS#10证书请求(参见代码示例中的第一个函数),需要为它创建PKCS#7签名消息。好吧,我解释一下我的问题。如何使用javascript创建签名的PKCS#7消息? (理想情况下,它应该允许使用UI指定适当的证书。)
至于javascript,我知道这不是方便的方式,但是因为我必须在客户端(在浏览器中)处理它。此外,cert注册IX509CertificateRequestPkcs7接口的方法标记为[WebEnabled],所以我相信必须有办法做我所说的。
答案 0 :(得分:3)
您可以使用Forge在纯JS中执行PKCS#7和PKCS#10(在浏览器或node.js中工作):
答案 1 :(得分:1)
PKCS#7格式在rfc2315中使用ASN.1表示法定义。
ASN.1是用于定义数据结构的表示法。另外,还有DER编码规则定义ASN.1符号如何编码为二进制数据。
所以问题归结为"是否有任何实现ASN1的JS库?" 有some decoding libraries
但唯一的编码器是这一个:https://github.com/indutny/asn1.js
让我们深入了解。 PKCS#7的ASN.1如下:
ContentInfo ::= SEQUENCE {
contentType ContentType,
content
[0] EXPLICIT ANY DEFINED BY contentType OPTIONAL }
ContentType ::= OBJECT IDENTIFIER
这里我们需要了解什么是OBJECT IDENTIFIER。它是一个特殊的数字序列,定义了某种类型。 PKCS#7的有效对象标识符如下:
data OBJECT IDENTIFIER ::= { pkcs-7 1 }
signedData OBJECT IDENTIFIER ::= { pkcs-7 2 }
envelopedData OBJECT IDENTIFIER ::= { pkcs-7 3 }
signedAndEnvelopedData OBJECT IDENTIFIER ::= { pkcs-7 4 }
digestedData OBJECT IDENTIFIER ::= { pkcs-7 5 }
encryptedData OBJECT IDENTIFIER ::= { pkcs-7 6 }
pkcs-7是PKCS#7格式的对象标识符。
pkcs-7 OBJECT IDENTIFIER ::=
{ iso(1) member-body(2) US(840) rsadsi(113549)
pkcs(1) 7 }
如您所见,ANY DEFINED BY contentType
字段有content
修饰符。这意味着该字段可以是6种类型中的任何一种,具体取决于contentType字段的值。
好像你需要签名的消息,所以内容类型将是" signedData"
这如何转换为ASN1.js代码?你在这里:
var PKCS7_CONTENT_TYPES = {
"1 2 840 113549 1 7 1": "data",
"1 2 840 113549 1 7 2": "signedData",
"1 2 840 113549 1 7 3": "envelopedData",
"1 2 840 113549 1 7 4": "signedAndEnvelopedData",
"1 2 840 113549 1 7 5": "digestData",
"1 2 840 113549 1 7 6": "encryptedData",
};
var ContentInfo = asn1.define('ContentInfo', function() {
this.seq().obj(
this.key('contentType').objid(PKCS7_CONTENT_TYPES),
this.key('content').optional().explicit(0).any()
);
});
那么,如何使用这个ContentInfo?
var signedData = ...
contentInfoEncoded = ContentInfo.encode({
'contentType': 'signedData',
'content': signedData
})
继续......
答案 2 :(得分:0)
VBScript方法(它会提示选择证书):
Function SignMessage(Message)
Dim oUtils
Set oUtils = CreateObject("CAPICOM.Utilities")
Dim cpcSigner
Set cpcSigner = CreateObject("CAPICOM.Signer")
cpcSigner.Options = 2 'CAPICOM_CERTIFICATE_INCLUDE_END_ENTITY_ONLY
Dim cpcSignedData
Set cpcSignedData = CreateObject("CAPICOM.SignedData")
cpcSignedData.Content = oUtils.Base64Decode(Message)
SignMessage = cpcSignedData.Sign(cpcSigner, False)
End function
Javascript方法(由于JS中的编码字符串会小心你会得到损坏的签名,所以我建议使用VBScript 来签署客户端脚本中的数据因为它可以与JS互操作):
var CAPICOM_CERTIFICATE_INCLUDE_END_ENTITY_ONLY = 2;
SignMessage: function (message) {
var cpcSigner = new ActiveXObject("CAPICOM.Signer");
cpcSigner.Options = CAPICOM_CERTIFICATE_INCLUDE_END_ENTITY_ONLY;
var cpcSignedData = new ActiveXObject("CAPICOM.SignedData");
var oUtils = new ActiveXObject("CAPICOM.Utilities");
cpcSignedData.Content = oUtils.Base64Decode(message);
return cpcSignedData.Sign(cpcSigner, false);
}