1

我使用的是 GEMALTO USB Key SmartCard,我想在我的 PDF 文件中添加数字签名。

为此,我在谷歌上阅读了几篇关于这个主题的文章。经过这些阅读,我成功编写了一个 Javascript 代码,它可以从我的令牌中获取 PRIVATE_KEY、PUBLIC_KEY 和 SIGNATURE,如下所示:

var pkcs11js = require("pkcs11js");
var fs = require('fs');
var forge = require('node-forge');

var pkcs11 = new pkcs11js.PKCS11();
pkcs11.load("C:/Program Files/Gemalto/Classic Client/BIN/gclib.dll");

pkcs11.C_Initialize();

try {
    // Getting info about PKCS11 Module
    var module_info = pkcs11.C_GetInfo();
    console.log("1- INFO MODULE: ",module_info);
    // Getting list of slots
    var slots = pkcs11.C_GetSlotList(true);
    console.log("2- SLOTS: ",slots);

    var slot = slots[0];
    console.log("3- SLOT: ",slot);

    // Getting info about slot
    var slot_info = pkcs11.C_GetSlotInfo(slot);
    console.log("4- INFO SLOT: ",slot_info);

    // Getting info about token
    var token_info = pkcs11.C_GetTokenInfo(slot);
    console.log("5- INFO TOKEN: ",token_info);

    // Getting info about Mechanism
    var mechs = pkcs11.C_GetMechanismList(slot);
    console.log("6- MECHANISM: ",mechs);

    var mech_info = pkcs11.C_GetMechanismInfo(slot, mechs[0]);
    console.log("7- INFO MECHANISM: ",mech_info);

    var session = pkcs11.C_OpenSession(slot, pkcs11js.CKF_RW_SESSION | pkcs11js.CKF_SERIAL_SESSION);
    console.log("8- SESSION: ",session);

    // Getting info about Session
    var info = pkcs11.C_GetSessionInfo(session);
    pkcs11.C_Login(session, 1, "856489");
    console.log("9- INFO SESSION: ",info);

    /** MY CODE **/

       //-- GET Private Key --*/
       var keys = {privateKey: null, publicKey: null};

       pkcs11.C_FindObjectsInit(session, [
           { type: pkcs11js.CKA_CLASS, value: pkcs11js.CKO_PRIVATE_KEY },
           { type: pkcs11js.CKA_LABEL, value: "My RSA Private Key" }
       ]);
       var hObject = pkcs11.C_FindObjects(session);
       console.log("10-1/ hObject Private BEFORE WHILE: ",hObject)

       while (hObject) {
           var attrs = pkcs11.C_GetAttributeValue(session, hObject, [
               { type: pkcs11js.CKA_CLASS },
               { type: pkcs11js.CKA_TOKEN },
               { type: pkcs11js.CKA_LABEL }
           ]);
           keys.privateKey = hObject;
           hObject = pkcs11.C_FindObjects(session);
       }

       console.log("10-2/ hObject Private AFTER WHILE: ",hObject);
       console.log("Private KEY: ",keys.privateKey);
    pkcs11.C_FindObjectsFinal(session);

    //-- GET Public Key --*/
    pkcs11.C_FindObjectsInit(session, [
           { type: pkcs11js.CKA_CLASS, value: pkcs11js.CKO_PUBLIC_KEY },
           { type: pkcs11js.CKA_LABEL, value: "My RSA Public Key" }
       ]);
       var hObject = pkcs11.C_FindObjects(session);
       console.log("11-1/ hObject Public BEFORE WHILE: ",hObject)

       while (hObject) {
           var attrs = pkcs11.C_GetAttributeValue(session, hObject, [
               { type: pkcs11js.CKA_CLASS },
               { type: pkcs11js.CKA_TOKEN },
               { type: pkcs11js.CKA_LABEL }
           ]);

           keys.publicKey = hObject; 
           hObject = pkcs11.C_FindObjects(session);
       }
       console.log("11-1/ hObject Public AFTER WHILE: ",hObject);
       console.log("Public KEY: ",keys.publicKey); 
    pkcs11.C_FindObjectsFinal(session);

    let pdf = fs.readFileSync("C:/APEX/Projets/PDF_SignElec/Files/McGhan_AngularJS.pdf");
    const lastChar = pdf.slice(pdf.length - 1).toString();
        if (lastChar === '\n') {
            // remove the trailing new line
            pdf = pdf.slice(0, pdf.length - 1);
        }
        console.log("12- PDF File: ",pdf);
        //console.log("13- PDF File: ",pdf.toString('binary'));

     //-- Signature --
    pkcs11.C_SignInit(session, { mechanism: pkcs11js.CKM_SHA256_RSA_PKCS }, keys.privateKey);
    pkcs11.C_SignUpdate(session, pdf);

    var signature = pkcs11.C_SignFinal(session, Buffer(256));
    console.log("14- Signature: ",signature.toString("hex"));

        //Vérification
        pkcs11.C_VerifyInit(session, { mechanism: pkcs11js.CKM_SHA256_RSA_PKCS }, keys.publicKey);
        pkcs11.C_VerifyUpdate(session, pdf);


        var verify = pkcs11.C_VerifyFinal(session, signature);
        console.log("15- Vérification: ",verify);
    /* END CODE */

}
catch(e){
    console.error(e);
}
finally {
    pkcs11.C_Finalize();
}

我得到了这个结果:

C:\Program Files\nodejs\node.exe --inspect-brk=7980 myExample_1.js
Debugger listening on ws://127.0.0.1:7980/efa52a7c-ca29-45e8-84a3-8e7c17fefa32
For help, see: https://nodejs.org/en/docs/inspector
Debugger attached.
null: 1- INFO MODULE:
null: Object {cryptokiVersion: Object, manufacturerID: "Gemplus                         ", flags: 0, libraryDescription: "PKCS#11 Cryptoki Multiplexer    ", libraryVersion: Object}
null: 2- SLOTS:
null: Array(1) [Uint8Array(4)]
null: 3- SLOT:
null: Uint8Array(4) [1, 0, 0, 0]
null: 4- INFO SLOT:
null: Object {slotDescription: "Gemalto USB Key Smart Card Reader 0               …", manufacturerID: "Gemalto                         ", flags: 7, hardwareVersion: Object, firmwareVersion: Object}
null: 5- INFO TOKEN:
null: Object {label: "GemP15-1                        ", manufacturerID: "Gemalto S.A.                    ", model: "Classic V3      ", serialNumber: "38C000AB63242A76", flags: 1037, …}
null: 6- MECHANISM:
null: Array(21) [1, 0, 5, 6, 64, 289, 290, 306, …]
null: 7- INFO MECHANISM:
null: Object {minKeySize: 1024, maxKeySize: 2048, flags: 404235}
null: 8- SESSION:
null: Uint8Array(4) [1, 0, 1, 0]
null: 9- INFO SESSION:
null: Object {slotID: Uint8Array(4), state: 2, flags: 6, deviceError: 4294938624}
null: 10-1/ hObject Private BEFORE WHILE:
null: Uint8Array(4) [1, 0, 0, 0]
10-2/ hObject Private AFTER WHILE:  null
null: Private KEY:
null: Uint8Array(4) [2, 0, 0, 0]
null: 11-1/ hObject Public BEFORE WHILE:
null: Uint8Array(4) [3, 0, 0, 0]
11-1/ hObject Public AFTER WHILE:  null
null: Public KEY:
null: Uint8Array(4) [6, 0, 0, 0]
null: 12- PDF File:
null: Buffer(1187270) [37, 80, 68, 70, 45, 49, 46, 53, …]
14- Signature:  04106c0898ef2ad59c2f873c74d7ef84f4139b817710cd2b8948880175a568a4dc3220fab76d637ad018252e78298c988f79d2c17e79e51dd2a5b0ec10e60644c90fd1573d420d0e6102a23c63b5b33d6da2a5fb424517c497d654fa860fe3043ff671be5bd32545d20fcd14b9172be0cb0ed8b4450de75ba21a353471b0226221772fa64b4fad452e6b240d39d9241895bd407ecbe66e91693aa2d4ed1fc9f60125f7b99e04a1d84d9a9dc9f3822bfe03e2a0f8b1a21c9550b453517477b31e2a6ba365fb4e2773eee669423669e0e6ec2fd0a798af82debec8e783c854827d5e5cad860af5183f0e8efde68c0c18436852c020d7f4102a20e597ef6a70b90f
15- Vérification:  true
(node:13172) [DEP0005] DeprecationWarning: Buffer() is deprecated due to security and usability issues. Please use the Buffer.alloc(), Buffer.allocUnsafe(), or Buffer.from() methods instead.

现在我的问题是:如何从我的 javascript 令牌中获取 X.509 证书,并将其放入我的 pdf 文件中?

谢谢你的帮助。

4

0 回答 0