forked from vbuch/node-signpdf
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathwebcrypto-external.js
More file actions
105 lines (91 loc) · 4.14 KB
/
webcrypto-external.js
File metadata and controls
105 lines (91 loc) · 4.14 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
var fs = require('fs');
var path = require('path');
var signpdf = require('@signpdf/signpdf').default;
var plainAddPlaceholder = require('@signpdf/placeholder-plain').plainAddPlaceholder;
var ExternalSigner = require('@signpdf/signer').ExternalSigner;
var crypto = require('crypto');
var createCertificate = require('./utils').createCertificate;
// ExternalSigner implementation using the WebCrypto API
// Note that this is just an example implementation of the ExternalSigner abstract class.
// WebCrypto signing can also be implemented more easily by subclassing the Signer abstract
// class directly, as is done in the `webcrypto.js` example script.
class CryptoSigner extends ExternalSigner {
// 'SHA-256', 'SHA-384' or 'SHA-512' are supported by webcrypto
supportedHashAlgorithms = ['SHA-256', 'SHA-384', 'SHA-512'];
// 'RSASSA-PKCS1-v1_5', 'RSA-PSS' or 'ECDSA' are supported by webcrypto
supportedSignAlgorithms = ['RSASSA-PKCS1-v1_5', 'RSA-PSS', 'ECDSA'];
constructor(signAlgorithm = 'ECDSA', hashAlgorithm = 'SHA-512') {
super();
// Verify and set signature and hash algorithms
if (!this.supportedSignAlgorithms.includes(signAlgorithm)) {
throw new Error(`Signature algorithm ${signAlgorithm} is not supported by WebCrypto.`);
}
this.signAlgorithm = signAlgorithm;
if (!this.supportedHashAlgorithms.includes(hashAlgorithm)) {
throw new Error(`Hash algorithm ${hashAlgorithm} is not supported by WebCrypto.`);
}
this.hashAlgorithm = hashAlgorithm;
// Salt lengths for RSA-PSS algorithm used by PKI.js
// If you want to modify these, the crypto.getSignatureParameters
// method needs to be overridden in the getCrypto function.
this.saltLengths = {
'SHA-256': 32,
'SHA-384': 48,
'SHA-512': 64,
}
this.cert = undefined;
this.key = undefined;
}
async getCertificate() {
// Create a new keypair and certificate
let params = {namedCurve: 'P-256'}; // EC parameters
if (this.signAlgorithm.startsWith("RSA")) {
// RSA parameters
params = {
modulusLength: 2048,
publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
hash: this.hashAlgorithm,
};
}
const keypair = await crypto.subtle.generateKey({
name: this.signAlgorithm,
...params,
}, true, ['sign', 'verify']);
this.cert = await createCertificate(keypair, this.hashAlgorithm);
this.key = keypair.privateKey;
return this.cert;
}
async getSignature(_hash, data) {
// WebCrypto's sign function automatically computes the hash of the passed data before signing.
return crypto.subtle.sign({
name: this.signAlgorithm,
hash: this.hashAlgorithm, // Required for ECDSA algorithm
saltLength: this.saltLengths[this.hashAlgorithm], // Required for RSA-PSS algorithm
}, this.key, data);
}
}
function work() {
// contributing.pdf is the file that is going to be signed
var sourcePath = path.join(__dirname, '/../../../resources/contributing.pdf');
var pdfBuffer = fs.readFileSync(sourcePath);
// Create new CryptoSigner
var signAlgorithm = 'ECDSA';
var hashAlgorithm = 'SHA-512';
var signer = new CryptoSigner(signAlgorithm, hashAlgorithm);
// The PDF needs to have a placeholder for a signature to be signed.
var pdfWithPlaceholder = plainAddPlaceholder({
pdfBuffer: pdfBuffer,
reason: 'The user is declaring consent through JavaScript.',
contactInfo: 'signpdf@example.com',
name: 'John Doe',
location: 'Free Text Str., Free World',
});
// pdfWithPlaceholder is now a modified Buffer that is ready to be signed.
signpdf.sign(pdfWithPlaceholder, signer)
.then(function (signedPdf) {
// signedPdf is a Buffer of an electronically signed PDF. Store it.
var targetPath = path.join(__dirname, '/../output/webcrypto-external.pdf');
fs.writeFileSync(targetPath, signedPdf);
});
}
work();