最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

cryptography - How to create signed PKCS#7 message with javascript? - Stack Overflow

programmeradmin0浏览0评论

I'm trying to create signed PKCS#7 message for PKCS#10 certifacate request on client-side with javascript.

There are good examples on PKCS#10: .aspx

But I need to create PKCS#7 and cannot figure out how to do it. There is a lack of examples (actually no at all) on official documentation for CertEnroll: (v=vs.85).aspx

I've ended up with this code:

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;
}

Is there any way to create PKCS#7 message with javascript?

UPDATE: I've already had PKCS#10 cert request (see the first function in code sample) and need to create PKCS#7 signed message for it. Ok, I paraphrase my question. How to create signed PKCS#7 message with javascript? (Ideally, it should allow to specify proper cert with UI.)

As for javascript I understand that it's not the convenient way, but suitable because I must to deal with it on client-side (in browser). Moreover, cert enroll IX509CertificateRequestPkcs7 interface has methods marked as [WebEnabled], so I believe there must be the way to do what I state.

I'm trying to create signed PKCS#7 message for PKCS#10 certifacate request on client-side with javascript.

There are good examples on PKCS#10: http://blogs.msdn./b/alejacma/archive/2009/01/28/how-to-create-a-certificate-request-with-certenroll-javascript.aspx

But I need to create PKCS#7 and cannot figure out how to do it. There is a lack of examples (actually no at all) on official documentation for CertEnroll: http://msdn.microsoft./en-us/library/windows/desktop/aa374850(v=vs.85).aspx

I've ended up with this code:

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;
}

Is there any way to create PKCS#7 message with javascript?

UPDATE: I've already had PKCS#10 cert request (see the first function in code sample) and need to create PKCS#7 signed message for it. Ok, I paraphrase my question. How to create signed PKCS#7 message with javascript? (Ideally, it should allow to specify proper cert with UI.)

As for javascript I understand that it's not the convenient way, but suitable because I must to deal with it on client-side (in browser). Moreover, cert enroll IX509CertificateRequestPkcs7 interface has methods marked as [WebEnabled], so I believe there must be the way to do what I state.

Share Improve this question edited Nov 16, 2012 at 12:56 Vladislav asked Nov 14, 2012 at 12:38 VladislavVladislav 2,0151 gold badge33 silver badges40 bronze badges 6
  • You've provided a large block of code. What exactly is wrong with it? Does it pile? Does it produce an error? – Duncan Jones Commented Nov 14, 2012 at 14:20
  • I've put noticeable ments in the code (marked with /******/). In fact, I try to create signed PKCS#7 message and don't know how to provide SignerCert. Do not rule out there may be the different way to achieve this. – Vladislav Commented Nov 16, 2012 at 6:03
  • There is no such thing as a PKCS#7 certificate request. You might want to encrypt the PKCS#10 certificate request though (e.g. to keep the information that is to be contained in the certificate confidential). But for that to work you need more than a document that states that it has to be PKCS#7 encoded, you need something that defines the precise PKCS#7 envelope. – Maarten Bodewes Commented Nov 16, 2012 at 11:34
  • For signing you also need access to the private key, although the private keys are normally linked with the certificate. Providing a pin or password for access ro the key may be tricky too. – Maarten Bodewes Commented Nov 16, 2012 at 11:37
  • Did you finally figure it out? I'm looking for something similar – Riho Commented Jan 25, 2013 at 12:34
 |  Show 1 more ment

3 Answers 3

Reset to default 4

You can do PKCS#7 and PKCS#10 in pure JS using Forge (works in browser or node.js):

https://github./digitalbazaar/forge#pkcs7

https://github./digitalbazaar/forge#pkcs10

PKCS#7 format is defined in rfc2315 using ASN.1 notation.

ASN.1

ASN.1 is a notation for defining data structures. Additionaly, there is also DER - encoding rules that define how ASN.1 notation is encoded as binary data.

ASN1.js encoder

So the question boils down to "are there any JS-libraries that implements ASN1?" There are some decoding libraries

But the only encoder is this one: https://github./indutny/asn1.js

ContentInfo and types

Let's dive deeper. The ASN.1 for PKCS#7 follows:

ContentInfo ::= SEQUENCE {
  contentType ContentType,
  content
    [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL }

ContentType ::= OBJECT IDENTIFIER

Here we need to understand what is OBJECT IDENTIFIER. It is a special sequence of numbers that defines some type. Valid object identifiers for PKCS#7 follow:

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 is an object identifier for PKCS#7 format.

pkcs-7 OBJECT IDENTIFIER ::=
  { iso(1) member-body(2) US(840) rsadsi(113549)
      pkcs(1) 7 }

As you can see, there's ANY DEFINED BY contentType modifier for the content field. It means that this field can be any of 6 types depending on the value of contentType field.

It seems like you need signed message, so the content type would be "signedData"

ContentInfo encoding using JS

How this translates into ASN1.js code? Here you're:

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()
    );
});

So, how to use this ContentInfo?

var signedData = ...
   contentInfoEncoded = ContentInfo.encode({
     'contentType': 'signedData',
     'content': signedData
   })

SignedData

To be continued...

VBScript method (it will prompt to choose certificate):

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 method (be carefull due to encoding strings in JS you will get corrupted signature, so I suggest to use VBScript for signing data in your client scripts since it interoperable with 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);
}
发布评论

评论列表(0)

  1. 暂无评论