@@ -8,6 +8,10 @@ import {convertBuffer, SignPdfError, Signer} from '@signpdf/utils';
88 */
99
1010export class P12Signer extends Signer {
11+ hashAlgorithm = 'SHA-256' ;
12+
13+ signAlgorithm = 'RSASSA-PKCS1-v1_5' ;
14+
1115 /**
1216 * @param {Buffer | Uint8Array | string } p12Buffer
1317 * @param {SignerOptions } additionalOptions
@@ -22,23 +26,9 @@ export class P12Signer extends Signer {
2226 passphrase : '' ,
2327 ...additionalOptions ,
2428 } ;
25- this . cert = forge . util . createBuffer ( buffer . toString ( 'binary' ) ) ;
26- }
27-
28- /**
29- * @param {Buffer } pdfBuffer
30- * @param {Date | undefined } signingTime
31- * @returns {Buffer }
32- */
33- async sign ( pdfBuffer , signingTime = undefined ) {
34- if ( ! ( pdfBuffer instanceof Buffer ) ) {
35- throw new SignPdfError (
36- 'PDF expected as Buffer.' ,
37- SignPdfError . TYPE_INPUT ,
38- ) ;
39- }
4029
4130 // Convert Buffer P12 to a forge implementation.
31+ this . cert = forge . util . createBuffer ( buffer . toString ( 'binary' ) ) ;
4232 const p12Asn1 = forge . asn1 . fromDer ( this . cert ) ;
4333 const p12 = forge . pkcs12 . pkcs12FromAsn1 (
4434 p12Asn1 ,
@@ -48,69 +38,59 @@ export class P12Signer extends Signer {
4838
4939 // Extract safe bags by type.
5040 // We will need all the certificates and the private key.
51- const certBags = p12 . getBags ( {
41+ this . certBags = p12 . getBags ( {
5242 bagType : forge . pki . oids . certBag ,
5343 } ) [ forge . pki . oids . certBag ] ;
54- const keyBags = p12 . getBags ( {
44+ this . keyBags = p12 . getBags ( {
5545 bagType : forge . pki . oids . pkcs8ShroudedKeyBag ,
5646 } ) [ forge . pki . oids . pkcs8ShroudedKeyBag ] ;
47+ }
5748
58- const privateKey = keyBags [ 0 ] . key ;
59- // Here comes the actual PKCS#7 signing.
60- const p7 = forge . pkcs7 . createSignedData ( ) ;
61- // Start off by setting the content.
62- p7 . content = forge . util . createBuffer ( pdfBuffer . toString ( 'binary' ) ) ;
63-
64- // Then add all the certificates (-cacerts & -clcerts)
65- // Keep track of the last found client certificate.
49+ /**
50+ * Retrieve all certificates from the safe bag and determine the signing certificate .
51+ * @returns { Promise<Uint8Array[]> }
52+ */
53+ async getCertificate ( ) {
54+ const privateKey = this . keyBags [ 0 ] . key ;
55+ // Retrieve all the certificates (-cacerts & -clcerts)
56+ // Keep track of the last found client certificate matching the private key .
6657 // This will be the public key that will be bundled in the signature.
67- let certificate ;
68- Object . keys ( certBags ) . forEach ( ( i ) => {
69- const { publicKey} = certBags [ i ] . cert ;
70-
71- p7 . addCertificate ( certBags [ i ] . cert ) ;
58+ let signCertFound = false ;
59+ const certificates = [ ] ;
60+ Object . values ( this . certBags ) . forEach ( ( bag ) => {
61+ const { publicKey} = bag . cert ;
7262
7363 // Try to find the certificate that matches the private key.
7464 if ( privateKey . n . compareTo ( publicKey . n ) === 0
7565 && privateKey . e . compareTo ( publicKey . e ) === 0
7666 ) {
77- certificate = certBags [ i ] . cert ;
67+ // Insert signing certificate in front
68+ certificates . unshift ( bag . cert ) ;
69+ signCertFound = true ;
70+ } else {
71+ // Insert all other certificates at the end
72+ certificates . push ( bag . cert ) ;
7873 }
7974 } ) ;
8075
81- if ( typeof certificate === 'undefined' ) {
76+ if ( ! signCertFound ) {
8277 throw new SignPdfError (
8378 'Failed to find a certificate that matches the private key.' ,
8479 SignPdfError . TYPE_INPUT ,
8580 ) ;
8681 }
82+ // Convert certificates to their binary representation
83+ return certificates . map ( ( cert ) => Buffer . from ( forge . asn1 . toDer ( forge . pki . certificateToAsn1 ( cert ) ) . getBytes ( ) , 'binary' ) ) ;
84+ }
8785
88- // Add a sha256 signer. That's what Adobe.PPKLite adbe.pkcs7.detached expects.
89- // Note that the authenticatedAttributes order is relevant for correct
90- // EU signature validation:
91- // https://ec.europa.eu/digital-building-blocks/DSS/webapp-demo/validation
92- p7 . addSigner ( {
93- key : privateKey ,
94- certificate,
95- digestAlgorithm : forge . pki . oids . sha256 ,
96- authenticatedAttributes : [
97- {
98- type : forge . pki . oids . contentType ,
99- value : forge . pki . oids . data ,
100- } , {
101- type : forge . pki . oids . signingTime ,
102- // value can also be auto-populated at signing time
103- value : signingTime ?? new Date ( ) ,
104- } , {
105- type : forge . pki . oids . messageDigest ,
106- // value will be auto-populated at signing time
107- } ,
108- ] ,
109- } ) ;
110-
111- // Sign in detached mode.
112- p7 . sign ( { detached : true } ) ;
113-
114- return Buffer . from ( forge . asn1 . toDer ( p7 . toAsn1 ( ) ) . getBytes ( ) , 'binary' ) ;
86+ /**
87+ * Retrieve the private key from the safe bag.
88+ * @returns {Promise<Uint8Array> }
89+ */
90+ async getKey ( ) {
91+ const privateKey = this . keyBags [ 0 ] . key ;
92+ // Convert private key to its pkcs8 binary representation
93+ const pkcs8 = forge . pki . wrapRsaPrivateKey ( forge . pki . privateKeyToAsn1 ( privateKey ) ) ;
94+ return Buffer . from ( forge . asn1 . toDer ( pkcs8 ) . getBytes ( ) , 'binary' ) ;
11595 }
11696}
0 commit comments