使用 X509 证书 + 智能卡的 Web 签名

标签 web x509certificate smartcard fortify

我正在尝试向我的网络应用程序添加签名功能。

签名必须使用智能卡进行。因此,在搜索了很多地方之后,我发现了webcrypto-socket(https://peculiarventures.github.io/webcrypto-local/docs/) - Webcrypto套接字模块实现了Crypto接口(interface)并使用Fortify应用程序进行加密实现。 p>

然后,我可以登录我的应用程序,但它生成的签名不是有效的 PKCS 签名,它仅返回签名哈希值,而没有公共(public)证书。

我的代码基于以下示例:https://peculiarventures.github.io/fortify-examples/example5.html

此外,欢迎对 webcrypto-socket 和 fortify 发表评论!

我正在做这样的事情,其中​​提供者和证书按照 fortify 的建议填写:

function sign() {
    var provider;
    var cert;
    Promise.resolve()
        .then(function () {
            var providerID = document.getElementById("providers").value;
            return ws.getCrypto(providerID)
        })
        .then(function (crypto) {
            provider = crypto;
          setEngine('subtle', crypto, 
    new CryptoEngine({ name: 'subtle', crypto: crypto, subtle: crypto.subtle }));

            return GetCertificate(provider,
                document.getElementById("certificates").value);
        })
        .then(function (certificate) {
            cert = certificate;
            return GetCertificateKey("private", provider,
                document.getElementById("certificates").value);
        })
        .then(function (key) {
            if (!key) {
                throw new Error("Certificate doesn't have private key");
            }

            var textToSignElement = document.getElementById("textToSign");
            var signatureResultElement = 
                document.getElementById("signatureResult");
            signDataElement(textToSignElement, signatureResultElement, 
                cert, key, provider);

        })
}

function signDataElement(textToSignElement, signatureResultElement, 
    key, cert, provider) {
    var message = pvtsutils.Convert.FromBase64(hashElement.value);
    var hashAlg = key.algorithm.hash.name;
    var sequence = Promise.resolve();
    sequence = sequence.then(() => provider.subtle.digest({ name: hashAlg },
        new Uint8Array(message)));
    var cmsSignedSimpl = null;
    var messHex = null;
    var certRaw = null;

    sequence = sequence.then(function (res) {
        messHex = res;
        return GetCertificateAsPEM(provider, cert);
    });

    //region Combine all signed extensions
    sequence = sequence.then(result => {
        certRaw = result;
        var signedAttr = [];

        signedAttr.push(new Attribute({
            type: "1.2.840.113549.1.9.3",
            values: [new ObjectIdentifier({ value: "1.2.840.113549.1.7.1" })]
        })); // contentType

        signedAttr.push(new Attribute({
            type: "1.2.840.113549.1.9.5",
            values: [new UTCTime({ valueDate: new Date() })]
        })); // signingTime

        signedAttr.push(new Attribute({
            type: "1.2.840.113549.1.9.4",
            values: [new OctetString({ valueHex: messHex})]
        })); // messageDigest

        return signedAttr;
    });

    sequence = sequence.then(signedAttr => {
        var asn1 = fromBER(PemToDer(certRaw));
        var newCert = new Certificate({ schema: asn1.result });

        newCert.issuer.typesAndValues.push(new AttributeTypeAndValue({
            type: "2.5.4.3", // Common name
            value: new BmpString({ value: cert.issuerName })
        }));
        cmsSignedSimpl = new SignedData({
            version: 1,
            encapContentInfo: new EncapsulatedContentInfo({
                eContentType: "1.2.840.113549.1.7.1" // "data" content type
            }),
            signerInfos: [new SignerInfo({
                version: 1,
                sid: new IssuerAndSerialNumber({
                    issuer: newCert.issuer,
                    serialNumber: newCert.serialNumber
                }),
                signedAttrs: new SignedAndUnsignedAttributes({
                    type: 0,
                    attributes: signedAttr
                })
            })],
            certificates: [newCert]
        });
        return cmsSignedSimpl.sign(key, 0, hashAlg, message)
    });

    sequence = sequence.then(() => {
        var cmsSignedSchema = cmsSignedSimpl.toSchema(true);

        var cmsContentSimp = new ContentInfo({
            contentType: "1.2.840.113549.1.7.2",
            content: cmsSignedSchema
        });

        var _cmsSignedSchema = cmsContentSimp.toSchema();

        //region Make length of some elements in "indefinite form"
        _cmsSignedSchema.lenBlock.isIndefiniteForm = true;

        var block1 = _cmsSignedSchema.valueBlock.value[1];
        block1.lenBlock.isIndefiniteForm = true;

        var block2 = block1.valueBlock.value[0];
        block2.lenBlock.isIndefiniteForm = true;

        //endregion

       return _cmsSignedSchema.toBER(false);
    }, error => Promise.reject(`Erorr during signing of CMS Signed Data: ${error}`));

    sequence.then((certificateBuffer) => {
        var certSimplString = String.fromCharCode.apply(null, 
            new Uint8Array(certificateBuffer));

        signatureElement.value = formatPEM(window.btoa(certSimplString));

        alert("Certificate created successfully!");
    })

    return sequence;
}

function GetCertificate(provider, certID) {
    var certID;
    return provider.certStorage.getItem(certID)
        .then(function (cert) {
            return cert;
        });
}

function GetCertificateAsPEM(provider, cert) {
    return provider.certStorage.exportCert('PEM', cert);
}

signDataElement基于https://pkijs.org/examples/CMSSigned_complex_example.html

最佳答案

我们将 Hancock ( https://fortifyapp.com ) 中的 Fortify ( https://hancock.ink ) 与 PKIjs ( https://pkijs.org ) 和 CAdESjs ( https://github.com/PeculiarVentures/CAdES.js ) 结合使用来创建 CMS 签名。

您可以在此处查看基于 PKIjs 的 JS 基本 CMS 示例:https://pkijs.org/examples/CMSSigned_complex_example.html

您需要向我们提供您正在做的事情的示例,我们可以告诉您需要采取哪些不同的做法。

瑞恩

关于使用 X509 证书 + 智能卡的 Web 签名,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51153900/

相关文章:

java - J3D081 全局平台个性化

c# - 在 C# 中从 ATR 确定设施代码和卡号

python - 调用 python 脚本并在网页上填充结果

php - 在 PHP 中使用 X509 证书加密数据

java - 如何在Java中读取X.509的扩展?

c# - 在代码中将 X509 证书添加到商店

apache - 如何使用托管在 Ubuntu 中的 nginx 在 docker 中启用 SSL

javascript - Internet Explorer Web 浏览器中不显示内容

html - 在html代码上自动播放wav文件

c++ - 智能卡获取响应返回状态 6D00