import forge from 'node-forge' ; import * as certUtil from './cert.util' ; export const getSignature = ( pdfWithByteRange , p12Buffer , placeholderLength , certPassword ) : string => { const p12Data = certUtil . getDataFromP12Cert ( p12Buffer , certPassword ) ; const certBags = certUtil . getCertBags ( p12Data ) ; const keyBags = getKeyBags ( p12Data ) ; const privateKey = getPrivateKey ( keyBags ) ; const p7 = forge . pkcs7 . createSignedData ( ) ; p7 . content = forge . util . createBuffer ( pdfWithByteRange . toString ( 'binary' ) ) ; const certificate = getCertificate ( p7 , certBags , privateKey ) ; const signer = getSigner ( privateKey , certificate ) ; p7 . addSigner ( signer ) ; p7 . sign ( { detached : true } ) ; const rawSignature = getRawSignature ( p7 , placeholderLength ) ; let signature = getSignatureFromRawSignature ( rawSignature , placeholderLength ) ; return signature ; } ; export const getOnlyRawSignature = ( pdfWithByteRange , p12Buffer , placeholderLength , certPassword ) : string => { const p12Data = certUtil . getDataFromP12Cert ( p12Buffer , certPassword ) ; const certBags = certUtil . getCertBags ( p12Data ) ; const keyBags = getKeyBags ( p12Data ) ; const privateKey = getPrivateKey ( keyBags ) ; const p7 = forge . pkcs7 . createSignedData ( ) ; p7 . content = forge . util . createBuffer ( pdfWithByteRange . toString ( 'binary' ) ) ; const certificate = getCertificate ( p7 , certBags , privateKey ) ; const signer = getSigner ( privateKey , certificate ) ; p7 . addSigner ( signer ) ; p7 . sign ( { detached : true } ) ; const rawSignature = getRawSignature ( p7 , placeholderLength ) ; return rawSignature ; } ; const getKeyBags = ( p12 ) : forge . pkcs12 . Bag [ ] => { const keyBags = p12 . getBags ( { bagType : forge . pki . oids . pkcs8ShroudedKeyBag } ) [ forge . pki . oids . pkcs8ShroudedKeyBag ] ; if ( ! keyBags ) { throw new Error ( 'KeyBags are not exist!' ) ; } return keyBags ; } ; const getPrivateKey = ( keyBags ) : forge . pki . PrivateKey => { const privateKey = keyBags [ keyBags . length - 1 ] . key ; if ( ! privateKey ) { throw new Error ( 'PrivateKey is not exists!' ) ; } return privateKey ; } ; const getCertificate = ( p7 , certBags , privateKey ) : forge . pki . Certificate => { let certificate ; Object . keys ( certBags ) . forEach ( ( value , index , array ) => { const publicKey = certBags [ index ] ?. cert ?. publicKey as forge . pki . PublicKey ; const rawCertificate = certBags [ index ] . cert as forge . pki . Certificate ; p7 . addCertificate ( rawCertificate ) ; certificate = getValidatedCertificate ( privateKey , publicKey , rawCertificate ) || certificate ; } ) ; if ( ! certificate ) { throw new Error ( 'Failed to find a certificate that matches the private key.' ) ; } return certificate ; } ; const getRawSignature = ( p7 , placeholderLength ) : string => { const rawSignature = forge . asn1 . toDer ( p7 . toAsn1 ( ) ) . getBytes ( ) ; if ( rawSignature . length * 2 > placeholderLength ) { throw new Error ( `Signature exceeds placeholder length: ${ rawSignature . length * 2 } > ${ placeholderLength }` ) ; } return rawSignature ; } ; export const getSignatureFromRawSignature = ( rawSignature , placeholderLength ) : string => { let signature = Buffer . from ( rawSignature , 'binary' ) . toString ( 'hex' ) ; signature += Buffer . from ( String . fromCharCode ( 0 ) . repeat ( placeholderLength / 2 - rawSignature . length ) ) . toString ( 'hex' ) ; return signature ; } ; const getSigner = ( privateKey , certificate ) : any => { return { key : privateKey , certificate , digestAlgorithm : forge . pki . oids . sha256 , authenticatedAttributes : [ { type : forge . pki . oids . contentType , value : forge . pki . oids . data , } , { type : forge . pki . oids . messageDigest , } , { type : forge . pki . oids . signingTime , value : new Date ( ) . toString ( ) , } , ] , } ; } ; const getValidatedCertificate = ( privateKey , publicKey , rawCertificate ) : forge . pki . Certificate | undefined => { let validatedCertificate = undefined ; const isPrivateKeyModulusSameAsPublicKeyModulus = ( privateKey as any ) . n . compareTo ( ( publicKey as any ) . n ) === 0 ; const isPrivateKeyExponentSameAsPublicKeyExponent = ( privateKey as any ) . e . compareTo ( ( publicKey as any ) . e ) === 0 ; if ( isPrivateKeyModulusSameAsPublicKeyModulus && isPrivateKeyExponentSameAsPublicKeyExponent ) { validatedCertificate = rawCertificate ; } return validatedCertificate ; } ;