refactor: extract createSigner factory and add signature algorithm OID

pull/14/head
Marcos Sanz Latorre 2026-08-04 22:12:14 +02:00
parent db7b45d445
commit 179fdf11e4
3 changed files with 101 additions and 23 deletions

View File

@ -240,6 +240,13 @@ z.RsaSigner = class{
return forge.pki.oids.sha256;
}
/**
* @return {string} the signature algorithm OID for the PKCS#7 SignerInfo
*/
getSignatureAlgorithmOid(){
return forge.pki.oids.sha256WithRSAEncryption;
}
/**
* @param {string} data
* @return {string} raw signature bytes
@ -252,6 +259,22 @@ z.RsaSigner = class{
}
};
/**
* Select a Signer implementation for the given key. Today only RSA keys are
* supported; this factory is the single place to extend the seam with ECDSA
* or post-quantum signers without touching the PDF assembly.
*
* @param {forge.pki.rsa.PrivateKey} privateKey
* @param {forge_cert} certificate
* @return {z.RsaSigner}
*/
z.createSigner = function(privateKey, certificate){
if(privateKey && privateKey.n && privateKey.e){
return new z.RsaSigner(privateKey, certificate);
}
throw new Error("Unsupported signing key type; only RSA keys are supported.");
};
z.PdfSigner = class{
/**
* @param {SignOption} signopt
@ -1053,7 +1076,7 @@ z.PdfSigner = class{
// so it can later be swapped without touching this code. node-forge still
// performs the RSA signing via the supplied key (shallow seam).
/** @type {z.RsaSigner} */
var signer = new z.RsaSigner(_this.privateKey, _this.cchain.getSignCert());
var signer = z.createSigner(_this.privateKey, _this.cchain.getSignCert());
// Add the signer. sha256 is what Adobe.PPKLite adbe.pkcs7.detached expects.
p7.addSigner({

View File

@ -197,8 +197,15 @@ async function main1(angle){
// test urlFetch
async function main2(){
// Boot a throwaway server on an ephemeral port so this test is self
// contained and cannot collide with an already running `npm run server`.
/** @type {http.Server} */
var srv = await startWebserver(0);
/** @type {number} */
var port = srv.address().port;
try{
/** @type {Uint8Array} */
var u8arr = await Zga.urlFetch("http://localhost:8080", {
var u8arr = await Zga.urlFetch("http://localhost:"+port, {
"headers": {
"testzb": "pineapple"
}
@ -210,10 +217,18 @@ async function main2(){
/** @type {string} */
var str = txtdec.decode(u8arr);
console.log(str);
}finally{
srv.close();
}
}
function webserver(){
require("http").createServer(function(req, res){
/**
* @param {number} port Port to listen on. 0 picks a free ephemeral port.
* @return {Promise<http.Server>} The listening server.
*/
function startWebserver(port){
/** @type {http.Server} */
var srv = require("http").createServer(function(req, res){
if(req.method == "GET"){
if(req.headers["testzb"]){
res.setHeader("Access-Control-Allow-Origin", "*");
@ -241,7 +256,14 @@ function webserver(){
res.statusMessage = "CORS OK";
res.end();
}
}).listen(8080, function(){console.log("Server http://localhost:8080")});
});
return new Promise(function(resolve, reject){
srv.once("error", reject);
srv.listen(port, function(){
console.log("Server http://localhost:"+srv.address().port);
resolve(srv);
});
});
}
async function main(){
@ -254,10 +276,21 @@ async function main(){
}
}
if(process.argv[2] == "webserver"){
webserver();
}else if(process.argv[2] == "fetch"){
main2();
}else{
main();
/**
* @param {Promise<*>} p
*/
function run(p){
p.catch(function(err){
console.error(err);
process.exitCode = 1;
});
}
if(process.argv[2] == "webserver"){
// Fixed port, because test.html expects the server on 8080.
run(startWebserver(8080));
}else if(process.argv[2] == "fetch"){
run(main2());
}else{
run(main());
}

View File

@ -28,3 +28,25 @@ test("RsaSigner reports SHA-256 as its digest algorithm OID", () => {
assert.strictEqual(signer.getDigestAlgorithmOid(), forge.pki.oids.sha256);
});
test("RsaSigner reports sha256WithRSAEncryption as its signature algorithm OID", () => {
const {privateKey, certificate} = makeKeyCert(3072);
const signer = new Zga.RsaSigner(privateKey, certificate);
assert.strictEqual(signer.getSignatureAlgorithmOid(), forge.pki.oids.sha256WithRSAEncryption);
});
test("createSigner returns an RsaSigner for an RSA key", () => {
const {privateKey, certificate} = makeKeyCert(3072);
const signer = Zga.createSigner(privateKey, certificate);
assert.ok(signer instanceof Zga.RsaSigner);
});
test("createSigner rejects an unsupported (non-RSA) key type", () => {
assert.throws(
() => Zga.createSigner({}, null),
/only RSA keys are supported/,
);
});