Skip to content
Snippets Groups Projects
Commit 2ee83d93 authored by Damyan Mitev's avatar Damyan Mitev :beach: Committed by Sasha Ilieva
Browse files

Revert "Make ES Lint happy"

This reverts commit bc806cba.
parent 2d1ecb82
No related branches found
No related tags found
3 merge requests!48269 implement workflow for signing already uploaded document dev,!47269 implement workflow for signing already uploaded document,!41268 convert odt file to pdf
...@@ -9,362 +9,367 @@ ...@@ -9,362 +9,367 @@
*/ */
import { import {
ObjectIdentifier, ObjectIdentifier,
UTCTime, UTCTime,
OctetString OctetString
} from 'asn1js'; } from 'asn1js';
import { import {
ContentInfo, ContentInfo,
SignedData, SignedData,
Attribute, Attribute,
SignerInfo, SignerInfo,
IssuerAndSerialNumber, IssuerAndSerialNumber,
SignedAndUnsignedAttributes, SignedAndUnsignedAttributes,
EncapsulatedContentInfo, EncapsulatedContentInfo,
getCrypto getCrypto
} from 'pkijs'; } from 'pkijs';
import { import {
parseCertificate, parseCertificate,
parsePrivateKey parsePrivateKey,
} from './signingUtilities'; } from './signingUtilities';
//keep this import to include the patched version of pdfjs library //keep this import to include the patched version of pdfjs library
import {PDFJS} from "../lib/pdfjs.parser.js"; import {PDFJS} from "../lib/pdfjs.parser.js";
function createXrefTable(xrefEntries) { function createXrefTable(xrefEntries) {
xrefEntries = sortOnKeys(xrefEntries); xrefEntries = sortOnKeys(xrefEntries);
let retVal = 'xref\n'; var retVal ='xref\n';
let last = -2; var last = -2;
for (let i in xrefEntries) { for(var i in xrefEntries) {
i = parseInt(i); i = parseInt(i);
if (typeof xrefEntries[i].offset === 'undefined') { continue; } if(typeof xrefEntries[i].offset === 'undefined') { continue; }
retVal += calcFlow(i, last, xrefEntries); retVal += calcFlow(i, last, xrefEntries);
const offset = xrefEntries[i].offset; var offset = xrefEntries[i].offset;
retVal += pad10(offset) + ' ' + pad5(xrefEntries[i].gen) + ' ' + (xrefEntries[i].free ? 'f' : 'n') + ' \n'; retVal += pad10(offset)+' '+pad5(xrefEntries[i].gen)+' '+(xrefEntries[i].free?'f':'n')+' \n';
last = i; last = i;
} }
return retVal; return retVal;
} }
function calcFlow(i, last, xrefEntries) { function calcFlow(i, last, xrefEntries) {
if (last + 1 === i) { return ''; } if(last + 1 === i) {return '';}
let count = 1; var count = 1;
while (typeof xrefEntries[i + count] !== 'undefined' && while(typeof xrefEntries[(i+count)] !== 'undefined'
typeof xrefEntries[i + count].offset !== 'undefined') { count++; } && typeof xrefEntries[(i+count)].offset !== 'undefined') {count ++;}
return i + ' ' + count + '\n'; return i + ' '+count+'\n';
} }
function createTrailer(topDict, startxref, sha256Hex, size, prev) { function createTrailer(topDict, startxref, sha256Hex, size, prev) {
let retVal = 'trailer <<\n'; var retVal ='trailer <<\n';
retVal += ' /Size ' + size + '\n'; retVal +=' /Size '+(size)+'\n';
const refRoot = topDict.getRaw('Root'); var refRoot = topDict.getRaw('Root');
if (typeof refRoot !== 'undefined') { if(typeof refRoot !== 'undefined') {
retVal += ' /Root ' + refRoot.num + ' ' + refRoot.gen + ' R\n'; retVal +=' /Root '+refRoot.num+' '+refRoot.gen+' R\n';
} }
const refInfo = topDict.getRaw('Info'); var refInfo = topDict.getRaw('Info');
if (typeof refInfo !== 'undefined') { if(typeof refInfo !== 'undefined') {
retVal += ' /Info ' + refInfo.num + ' ' + refInfo.gen + ' R\n'; retVal +=' /Info '+refInfo.num+' '+refInfo.gen+' R\n';
} }
retVal += ' /ID [<' + sha256Hex.substring(0,32) + '><' + sha256Hex.substring(32,64) + '>]\n'; retVal +=' /ID [<'+sha256Hex.substring(0,32)+'><'+sha256Hex.substring(32,64)+'>]\n';
if (typeof prev !== 'undefined') { if(typeof prev !== 'undefined' ) {
retVal += ' /Prev ' + prev + '\n'; retVal +=' /Prev '+prev+'\n';
} }
retVal += '>>\n'; retVal +='>>\n';
retVal += 'startxref\n'; retVal +='startxref\n';
retVal += startxref + '\n'; retVal +=startxref + '\n';
retVal += '%%EOF\n'; retVal +='%%EOF\n';
return retVal; return retVal;
} }
function createXrefTableAppend(xrefEntries) { function createXrefTableAppend(xrefEntries) {
xrefEntries = sortOnKeys(xrefEntries); xrefEntries = sortOnKeys(xrefEntries);
let retVal = 'xref\n'; var retVal ='xref\n';
let last = -2; var last = -2;
for (let i in xrefEntries) { for(var i in xrefEntries) {
i = parseInt(i); i = parseInt(i);
if (typeof xrefEntries[i].offset === 'undefined') { continue; } if(typeof xrefEntries[i].offset === 'undefined') { continue; }
retVal += calcFlow(i, last, xrefEntries); retVal += calcFlow(i, last, xrefEntries);
const offset = xrefEntries[i].offset; var offset = xrefEntries[i].offset;
retVal += pad10(offset) + ' ' + pad5(xrefEntries[i].gen) + ' ' + (xrefEntries[i].free ? 'f' : 'n') + ' \n'; retVal += pad10(offset)+' '+pad5(xrefEntries[i].gen)+' '+(xrefEntries[i].free?'f':'n')+' \n';
last = i; last = i;
} }
return retVal; return retVal;
} }
//http://stackoverflow.com/questions/10946880/sort-a-dictionary-or-whatever-key-value-data-structure-in-js-on-word-number-ke //http://stackoverflow.com/questions/10946880/sort-a-dictionary-or-whatever-key-value-data-structure-in-js-on-word-number-ke
function sortOnKeys(dict) { function sortOnKeys(dict) {
const sorted = []; var sorted = [];
for (const key in dict) { for(var key in dict) {
sorted[sorted.length] = key; sorted[sorted.length] = key;
} }
sorted.sort(); sorted.sort();
const tempDict = {}; var tempDict = {};
for (let i = 0; i < sorted.length; i++) { for(var i = 0; i < sorted.length; i++) {
tempDict[sorted[i]] = dict[sorted[i]]; tempDict[sorted[i]] = dict[sorted[i]];
} }
return tempDict; return tempDict;
} }
function removeFromArray(array, from, to) { function removeFromArray(array, from, to) {
const cutlen = to - from; var cutlen = to - from;
const buf = new Uint8Array(array.length - cutlen); var buf = new Uint8Array(array.length - cutlen);
for (let i = 0; i < from; i++) { for (var i = 0; i < from; i++) {
buf[i] = array[i]; buf[i] = array[i];
} }
for (let i = to, len = array.length; i < len; i++) { for (var i = to, len = array.length; i < len; i++) {
buf[i - cutlen] = array[i]; buf[i-cutlen] = array[i];
} }
return buf; return buf;
} }
function findXrefBlocks(xrefBlocks) { function findXrefBlocks(xrefBlocks) {
const num = xrefBlocks.length / 2; var num = xrefBlocks.length / 2;
const retVal = []; var retVal = [];
for (let i = 0; i < num; i++) { for (var i=0;i<num;i++) {
retVal.push({start: xrefBlocks[i], retVal.push({start: xrefBlocks[i], end: xrefBlocks[i+num]});
end: xrefBlocks[i + num]}); }
} return retVal;
return retVal;
} }
function convertUint8ArrayToBinaryString(u8Array) { function convertUint8ArrayToBinaryString(u8Array) {
let i, len = u8Array.length, bStr = ""; var i, len = u8Array.length, b_str = "";
for (i = 0; i < len; i++) { for (i=0; i<len; i++) {
bStr += String.fromCharCode(u8Array[i]); b_str += String.fromCharCode(u8Array[i]);
} }
return bStr; return b_str;
} }
function arrayObjectIndexOf(array, start, end, orig) { function arrayObjectIndexOf(array, start, end, orig) {
for (let i = 0, len = array.length; i < len; i++) { for(var i = 0, len = array.length; i < len; i++) {
if ((array[i].start === start) && (array[i].end === end) && (array[i].orig === orig)) { if ((array[i].start === start) && (array[i].end === end) && (array[i].orig === orig)) {
return i; return i;
}
} }
} return -1;
return -1;
} }
function pad10(num) { function pad10(num) {
const s = "000000000" + num; var s = "000000000" + num;
return s.substr(s.length - 10); return s.substr(s.length-10);
} }
function pad5(num) { function pad5(num) {
const s = "0000" + num; var s = "0000" + num;
return s.substr(s.length - 5); return s.substr(s.length-5);
} }
function pad2(num) { function pad2(num) {
const s = "0" + num; var s = "0" + num;
return s.substr(s.length - 2); return s.substr(s.length-2);
} }
function findRootEntry(xref) { function findRootEntry(xref) {
const rootNr = xref.root.objId.substring(0, xref.root.objId.length - 1); var rootNr = xref.root.objId.substring(0, xref.root.objId.length - 1);
return xref.entries[rootNr]; return xref.entries[rootNr];
} }
function findSuccessorEntry(xrefEntries, current) { function findSuccessorEntry(xrefEntries, current) {
//find it first //find it first
const currentOffset = current.offset; var currentOffset = current.offset;
let currentMin = Number.MAX_SAFE_INTEGER; var currentMin = Number.MAX_SAFE_INTEGER;
let currentMinIndex = -1; var currentMinIndex = -1;
for (const i in xrefEntries) { for(var i in xrefEntries) {
if (xrefEntries[i].offset > currentOffset) { if(xrefEntries[i].offset > currentOffset) {
if (xrefEntries[i].offset < currentMin) { if(xrefEntries[i].offset < currentMin) {
currentMin = xrefEntries[i].offset; currentMin = xrefEntries[i].offset;
currentMinIndex = i; currentMinIndex = i;
} }
} }
} }
if (currentMinIndex === -1) { if(currentMinIndex === -1) {
return current; return current;
} }
return xrefEntries[currentMinIndex]; return xrefEntries[currentMinIndex];
} }
function updateArray(array, pos, str) { function updateArray(array, pos, str) {
const upd = stringToUint8Array(str); var upd = stringToUint8Array(str);
for (let i = 0, len = upd.length; i < len; i++) { for (var i = 0, len=upd.length; i < len; i++) {
array[i + pos] = upd[i]; array[i+pos] = upd[i];
} }
return array; return array;
} }
function copyToEnd(array, from, to) { function copyToEnd(array, from, to) {
const buf = new Uint8Array(array.length + (to - from)); var buf = new Uint8Array(array.length + (to - from));
for (let i = 0, len = array.length; i < len; i++) { for (var i = 0, len=array.length; i < len; i++) {
buf[i] = array[i]; buf[i] = array[i];
} }
for (let i = 0, len = to - from; i < len; i++) { for (var i = 0, len=(to - from); i < len; i++) {
buf[array.length + i] = array[from + i]; buf[array.length + i] = array[from + i];
} }
return buf; return buf;
} }
function insertIntoArray(array, pos, str) { function insertIntoArray(array, pos, str) {
const ins = stringToUint8Array(str); var ins = stringToUint8Array(str);
const buf = new Uint8Array(array.length + ins.length); var buf = new Uint8Array(array.length + ins.length);
for (let i = 0; i < pos; i++) { for (var i = 0; i < pos; i++) {
buf[i] = array[i]; buf[i] = array[i];
} }
for (let i = 0; i < ins.length; i++) { for (var i = 0; i < ins.length; i++) {
buf[pos + i] = ins[i]; buf[pos+i] = ins[i];
} }
for (let i = pos; i < array.length; i++) { for (var i = pos; i < array.length; i++) {
buf[ins.length + i] = array[i]; buf[ins.length+i] = array[i];
} }
return buf; return buf;
} }
function stringToUint8Array(str) { function stringToUint8Array(str) {
const buf = new Uint8Array(str.length); var buf = new Uint8Array(str.length);
for (let i = 0, strLen = str.length; i < strLen; i++) { for (var i=0, strLen=str.length; i<strLen; i++) {
buf[i] = str.charCodeAt(i); buf[i] = str.charCodeAt(i);
} }
return buf; return buf;
} }
function uint8ArrayToString(buf, from, to) { function uint8ArrayToString(buf, from, to) {
if (typeof from !== 'undefined' && typeof to !== 'undefined') { if(typeof from !== 'undefined' && typeof to !== 'undefined') {
let s = ''; var s = '';
for (let i = from; i < to; i++) { for (var i=from; i<to; i++) {
s = s + String.fromCharCode(buf[i]); s = s + String.fromCharCode(buf[i]);
}
return s;
} }
return s; return String.fromCharCode.apply(null, buf);
}
return String.fromCharCode.apply(null, buf);
} }
function findFreeXrefNr(xrefEntries, used) {
used = typeof used !== 'undefined' ? used : [];
let inc = used.length;
for (let i = 1; i < xrefEntries.length; i++) {
const index = used.indexOf(i); function findFreeXrefNr(xrefEntries, used) {
const entry = xrefEntries["" + i]; used = typeof used !== 'undefined' ? used : [];
if (index === -1 && (typeof entry === 'undefined' || entry.free)) { var inc = used.length;
return i;
} for (var i=1;i<xrefEntries.length;i++) {
if (index !== -1) {
inc--; var index = used.indexOf(i);
var entry = xrefEntries[""+i];
if(index === -1 && (typeof entry === 'undefined' || entry.free)) {
return i;
}
if(index !== -1) {
inc--;
}
} }
} return xrefEntries.length + inc;
return xrefEntries.length + inc;
} }
function find(uint8, needle, start, limit) { function find(uint8, needle, start, limit) {
start = typeof start !== 'undefined' ? start : 0; start = typeof start !== 'undefined' ? start : 0;
limit = typeof limit !== 'undefined' ? limit : Number.MAX_SAFE_INTEGER; limit = typeof limit !== 'undefined' ? limit : Number.MAX_SAFE_INTEGER;
const search = stringToUint8Array(needle); var search = stringToUint8Array(needle);
let match = 0; var match = 0;
for (let i = start; i < uint8.length && i < limit; i++) { for(var i=start;i<uint8.length && i<limit;i++) {
if (uint8[i] === search[match]) { if(uint8[i] === search[match]) {
match++; match++;
} else { } else {
match = 0; match = 0;
if (uint8[i] === search[match]) { if(uint8[i] === search[match]) {
match++; match++;
} }
} }
if (match === search.length) { if(match === search.length) {
return (i + 1) - match; return (i + 1) - match;
}
} }
} return -1;
return -1;
} }
function findBackwards(uint8, needle, start, limit) { function findBackwards(uint8, needle, start, limit) {
start = typeof start !== 'undefined' ? start : uint8.length; start = typeof start !== 'undefined' ? start : uint8.length;
limit = typeof limit !== 'undefined' ? limit : Number.MAX_SAFE_INTEGER; limit = typeof limit !== 'undefined' ? limit : Number.MAX_SAFE_INTEGER;
const search = stringToUint8Array(needle); var search = stringToUint8Array(needle);
let match = search.length - 1; var match = search.length - 1;
for (let i = start; i >= 0 && i < limit; i--) { for(var i=start;i>=0 && i<limit;i--) {
if (uint8[i] === search[match]) { if(uint8[i] === search[match]) {
match--; match--;
} else { } else {
match = search.length - 1; match = search.length - 1;
if (uint8[i] === search[match]) { if(uint8[i] === search[match]) {
match--; match--;
} }
} }
if (match === 0) { if(match === 0) {
return i - 1; return i - 1;
}
} }
} return -1;
return -1;
} }
function strHex(s) { function strHex(s) {
let a = ""; var a = "";
for (let i = 0; i < s.length; i++) { for( var i=0; i<s.length; i++ ) {
a = a + pad2(s.charCodeAt(i).toString(16)); a = a + pad2(s.charCodeAt(i).toString(16));
} }
return a; return a;
} }
async function sha256(array) { async function sha256(array) {
const cryptoLib = getCrypto();
const digestTmpBuf = await cryptoLib.digest({ name: "SHA-256" }, array); const cryptoLib = getCrypto();
const digestTmpArray = new Uint8Array(digestTmpBuf); const digestTmpBuf = await cryptoLib.digest({ name: "SHA-256" }, array);
const digestTmpStr = uint8ArrayToString(digestTmpArray); const digestTmpArray = new Uint8Array(digestTmpBuf);
const sha256Hex = strHex(digestTmpStr); const digestTmpStr = uint8ArrayToString(digestTmpArray);
return sha256Hex; const sha256Hex = strHex(digestTmpStr);
return sha256Hex;
} }
function isSigInRoot(pdf) { function isSigInRoot(pdf) {
if (typeof pdf.acroForm === 'undefined') { if (typeof pdf.acroForm === 'undefined') {
return false; return false;
} }
return pdf.acroForm.get('SigFlags') === 3; return pdf.acroForm.get('SigFlags') === 3;
} }
function updateXrefOffset(xref, offset, offsetDelta) { function updateXrefOffset(xref, offset, offsetDelta) {
for (const i in xref.entries) { for(var i in xref.entries) {
if (xref.entries[i].offset >= offset) { if(xref.entries[i].offset >= offset) {
xref.entries[i].offset += offsetDelta; xref.entries[i].offset += offsetDelta;
}
} }
} for(var i in xref.xrefBlocks) {
for (const i in xref.xrefBlocks) { if(xref.xrefBlocks[i] >= offset) {
if (xref.xrefBlocks[i] >= offset) { xref.xrefBlocks[i] += offsetDelta;
xref.xrefBlocks[i] += offsetDelta; }
} }
}
} }
function updateXrefBlocks(xrefBlocks, offset, offsetDelta) { function updateXrefBlocks(xrefBlocks, offset, offsetDelta) {
for (const i in xrefBlocks) { for(var i in xrefBlocks) {
if (xrefBlocks[i].start >= offset) { if(xrefBlocks[i].start >= offset) {
xrefBlocks[i].start += offsetDelta; xrefBlocks[i].start += offsetDelta;
} }
if (xrefBlocks[i].end >= offset) { if(xrefBlocks[i].end >= offset) {
xrefBlocks[i].end += offsetDelta; xrefBlocks[i].end += offsetDelta;
}
} }
}
} }
function updateOffset(pos, offset, offsetDelta) { function updateOffset(pos, offset, offsetDelta) {
if (pos >= offset) { if(pos >= offset) {
return pos + offsetDelta; return pos + offsetDelta;
} }
return pos; return pos;
} }
function round256(x) { function round256(x) {
return (Math.ceil(x / 256) * 256) - 1; return (Math.ceil(x/256)*256) - 1;
} }
/** /**
...@@ -382,359 +387,349 @@ function round256(x) { ...@@ -382,359 +387,349 @@ function round256(x) {
* mm shall be the absolute value of the offset from UT in minutes (00–59) * mm shall be the absolute value of the offset from UT in minutes (00–59)
*/ */
function now(date) { function now(date) {
//date = typeof date !== 'undefined' ? date : new Date(); //date = typeof date !== 'undefined' ? date : new Date();
const yyyy = date.getFullYear().toString(); var yyyy = date.getFullYear().toString();
const MM = pad2(date.getMonth() + 1); var MM = pad2(date.getMonth() + 1);
const dd = pad2(date.getDate()); var dd = pad2(date.getDate());
const hh = pad2(date.getHours()); var hh = pad2(date.getHours());
const mm = pad2(date.getMinutes()); var mm = pad2(date.getMinutes());
const ss = pad2(date.getSeconds()); var ss = pad2(date.getSeconds());
return yyyy + MM + dd + hh + mm + ss + createOffset(date); return yyyy + MM + dd+ hh + mm + ss + createOffset(date);
} }
function createOffset(date) { function createOffset(date) {
const sign = date.getTimezoneOffset() > 0 ? "-" : "+"; var sign = (date.getTimezoneOffset() > 0) ? "-" : "+";
const offset = Math.abs(date.getTimezoneOffset()); var offset = Math.abs(date.getTimezoneOffset());
const hours = pad2(Math.floor(offset / 60)); var hours = pad2(Math.floor(offset / 60));
const minutes = pad2(offset % 60); var minutes = pad2(offset % 60);
return sign + hours + "'" + minutes; return sign + hours + "'" + minutes;
} }
async function newSig(pdf, root, rootSuccessor, date, signingCert, certificateChain, privateKey) { async function newSig(pdf, root, rootSuccessor, date, signingCert, certificateChain, privateKey) {
// {annotEntry} is the ref to the annot widget. If we enlarge the array, make sure all the offsets // {annotEntry} is the ref to the annot widget. If we enlarge the array, make sure all the offsets
// after the modification will be updated -> xref table and startxref // after the modification will be updated -> xref table and startxref
const annotEntry = findFreeXrefNr(pdf.xref.entries); var annotEntry = findFreeXrefNr(pdf.xref.entries);
// we'll store all the modifications we make, as we need to adjust the offset in the PDF // we'll store all the modifications we make, as we need to adjust the offset in the PDF
const offsetForm = find(pdf.stream.bytes, '<<', root.offset, rootSuccessor.offset) + 2; var offsetForm = find(pdf.stream.bytes, '<<', root.offset, rootSuccessor.offset) + 2;
//first we need to find the root element and add the following: //first we need to find the root element and add the following:
// //
// /AcroForm<</Fields[{annotEntry} 0 R] /SigFlags 3>> // /AcroForm<</Fields[{annotEntry} 0 R] /SigFlags 3>>
// //
const appendAcroForm = '/AcroForm<</Fields[' + annotEntry + ' 0 R] /SigFlags 3>>'; var appendAcroForm = '/AcroForm<</Fields['+annotEntry+' 0 R] /SigFlags 3>>';
//before we insert the acroform, we find the right place for annotentry //before we insert the acroform, we find the right place for annotentry
//we need to add Annots [x y R] to the /Type /Page section. We can do that by searching /Contents[ //we need to add Annots [x y R] to the /Type /Page section. We can do that by searching /Contents[
const pages = pdf.catalog.catDict.get('Pages'); var pages = pdf.catalog.catDict.get('Pages');
//get first page, we have hidden sig, so don't bother //get first page, we have hidden sig, so don't bother
const ref = pages.get('Kids')[0]; var ref = pages.get('Kids')[0];
const xref = pdf.xref.fetch(ref); var xref = pdf.xref.fetch(ref);
const offsetContentEnd = xref.get('#Contents_offset'); var offsetContentEnd = xref.get('#Contents_offset');
//we now search backwards, this is safe as we don't expect user content here //we now search backwards, this is safe as we don't expect user content here
let offsetContent = findBackwards(pdf.stream.bytes, '/Contents', offsetContentEnd); var offsetContent = findBackwards(pdf.stream.bytes, '/Contents', offsetContentEnd);
const appendAnnots = '/Annots[' + annotEntry + ' 0 R]\n '; var appendAnnots = '/Annots['+annotEntry+' 0 R]\n ';
//now insert string into stream //now insert string into stream
let array = insertIntoArray(pdf.stream.bytes, offsetForm, appendAcroForm); var array = insertIntoArray(pdf.stream.bytes, offsetForm, appendAcroForm);
//recalculate the offsets in the xref table, only update those that are affected //recalculate the offsets in the xref table, only update those that are affected
updateXrefOffset(pdf.xref, offsetForm, appendAcroForm.length); updateXrefOffset(pdf.xref, offsetForm, appendAcroForm.length);
offsetContent = updateOffset(offsetContent, offsetForm, appendAcroForm.length); offsetContent = updateOffset(offsetContent, offsetForm, appendAcroForm.length);
array = insertIntoArray(array, offsetContent, appendAnnots); var array = insertIntoArray(array, offsetContent, appendAnnots);
updateXrefOffset(pdf.xref, offsetContent, appendAnnots.length); updateXrefOffset(pdf.xref, offsetContent, appendAnnots.length);
offsetContent = -1; //not needed anymore, don't update when offset changes offsetContent = -1; //not needed anymore, don't update when offset changes
//Then add to the next free object (annotEntry) //Then add to the next free object (annotEntry)
//add right before the xref table or stream //add right before the xref table or stream
//if its a table, place element before the xref table //if its a table, place element before the xref table
// //
// sigEntry is the ref to the signature content. Next we need the signature object // sigEntry is the ref to the signature content. Next we need the signature object
const sigEntry = findFreeXrefNr(pdf.xref.entries, [annotEntry]); var sigEntry = findFreeXrefNr(pdf.xref.entries, [annotEntry]);
// //
// {annotEntry} 0 obj // {annotEntry} 0 obj
// <</F 132/Type/Annot/Subtype/Widget/Rect[0 0 0 0]/FT/Sig/DR<<>>/T(signature)/V Y 0 R>> // <</F 132/Type/Annot/Subtype/Widget/Rect[0 0 0 0]/FT/Sig/DR<<>>/T(signature)/V Y 0 R>>
// endobj // endobj
// //
const append = annotEntry + ' 0 obj\n<</F 132/Type/Annot/Subtype/Widget/Rect[0 0 0 0]/FT/Sig/DR<<>>/T(signature' + annotEntry + ')/V ' + sigEntry + ' 0 R>>\nendobj\n\n'; var append = annotEntry + ' 0 obj\n<</F 132/Type/Annot/Subtype/Widget/Rect[0 0 0 0]/FT/Sig/DR<<>>/T(signature'+annotEntry+')/V '+sigEntry+' 0 R>>\nendobj\n\n';
// we want the offset just before the last xref table or entry // we want the offset just before the last xref table or entry
const blocks = findXrefBlocks(pdf.xref.xrefBlocks); var blocks = findXrefBlocks(pdf.xref.xrefBlocks);
let offsetAnnot = blocks[0].start; var offsetAnnot = blocks[0].start;
array = insertIntoArray(array, offsetAnnot, append); array = insertIntoArray(array, offsetAnnot, append);
//no updateXrefOffset, as the next entry will be following //no updateXrefOffset, as the next entry will be following
// //
// {sigEntry} 0 obj // {sigEntry} 0 obj
// <</Contents <0481801e6d931d561563fb254e27c846e08325570847ed63d6f9e35 ... b2c8788a5> // <</Contents <0481801e6d931d561563fb254e27c846e08325570847ed63d6f9e35 ... b2c8788a5>
// /Type/Sig/SubFilter/adbe.pkcs7.detached/Location(Ghent)/M(D:20120928104114+02'00') // /Type/Sig/SubFilter/adbe.pkcs7.detached/Location(Ghent)/M(D:20120928104114+02'00')
// /ByteRange [A B C D]/Filter/Adobe.PPKLite/Reason(Test)/ContactInfo()>> // /ByteRange [A B C D]/Filter/Adobe.PPKLite/Reason(Test)/ContactInfo()>>
// endobj // endobj
// //
//the next entry goes below the above //the next entry goes below the above
let offsetSig = offsetAnnot + append.length; var offsetSig = offsetAnnot + append.length;
// Both {annotEntry} and {sigEntry} objects need to be added to the last xref table. The byte range needs // Both {annotEntry} and {sigEntry} objects need to be added to the last xref table. The byte range needs
// to be adjusted. Since the signature will always be in a gap, use first an empty sig // to be adjusted. Since the signature will always be in a gap, use first an empty sig
// to check the size, add ~25% size, then calculate the signature and place in the empty // to check the size, add ~25% size, then calculate the signature and place in the empty
// space. // space.
const start = sigEntry + ' 0 obj\n<</Contents <'; var start = sigEntry+ ' 0 obj\n<</Contents <';
const dummy = await signPki(signingCert, certificateChain, privateKey, stringToUint8Array('A'), date); var dummy = await sign_pki(signingCert, certificateChain, privateKey, stringToUint8Array('A'), date);
//TODO: Adobe thinks its important to have the right size, no idea why this is the case //TODO: Adobe thinks its important to have the right size, no idea why this is the case
const crypto = new Array(round256(dummy.length * 2)).join('0'); var crypto = new Array(round256(dummy.length * 2)).join( '0' );
const middle = '>\n/Type/Sig/SubFilter/adbe.pkcs7.detached/Location()/M(D:' + now(date) + '\')\n/ByteRange '; var middle = '>\n/Type/Sig/SubFilter/adbe.pkcs7.detached/Location()/M(D:'+now(date)+'\')\n/ByteRange ';
let byteRange = '[0000000000 0000000000 0000000000 0000000000]'; var byteRange = '[0000000000 0000000000 0000000000 0000000000]';
const end = '/Filter/Adobe.PPKLite/Reason()/ContactInfo()>>\nendobj\n\n'; var end = '/Filter/Adobe.PPKLite/Reason()/ContactInfo()>>\nendobj\n\n';
//all together //all together
const append2 = start + crypto + middle + byteRange + end; var append2 = start+crypto+middle+byteRange+end;
const offsetByteRange = start.length + crypto.length + middle.length; var offsetByteRange = start.length+crypto.length+middle.length;
array = insertIntoArray(array, offsetSig, append2); array = insertIntoArray(array, offsetSig, append2);
updateXrefOffset(pdf.xref, offsetAnnot, append2.length + append.length); updateXrefOffset(pdf.xref, offsetAnnot, append2.length + append.length);
//find the xref tables, remove them and also the EOF, as we'll write a new table //find the xref tables, remove them and also the EOF, as we'll write a new table
const xrefBlocks = findXrefBlocks(pdf.xref.xrefBlocks); var xrefBlocks = findXrefBlocks(pdf.xref.xrefBlocks);
for (const i in xrefBlocks) { for(var i in xrefBlocks) {
const oldSize = array.length; var oldSize = array.length;
array = removeFromArray(array, xrefBlocks[i].start, xrefBlocks[i].end); array = removeFromArray(array, xrefBlocks[i].start, xrefBlocks[i].end);
const length = array.length - oldSize; var length = array.length - oldSize;
updateXrefOffset(pdf.xref, xrefBlocks[i].start, length); updateXrefOffset(pdf.xref, xrefBlocks[i].start, length);
//check for %%EOF and remove it as well //check for %%EOF and remove it as well
const offsetEOF = find(array, '%%EOF', xrefBlocks[i].start, xrefBlocks[i].start + 20); var offsetEOF = find(array, '%%EOF', xrefBlocks[i].start, xrefBlocks[i].start+20);
if (offsetEOF > 0) { if(offsetEOF > 0) {
const lengthEOF = '%%EOF'.length; var lengthEOF = '%%EOF'.length;
array = removeFromArray(array, offsetEOF, offsetEOF + lengthEOF); array = removeFromArray(array, offsetEOF, offsetEOF + lengthEOF);
updateXrefOffset(pdf.xref, offsetEOF, -lengthEOF); updateXrefOffset(pdf.xref, offsetEOF, -lengthEOF);
updateXrefBlocks(xrefBlocks, offsetEOF, -lengthEOF); updateXrefBlocks(xrefBlocks, offsetEOF, -lengthEOF);
offsetAnnot = updateOffset(offsetAnnot, offsetEOF, -lengthEOF); offsetAnnot = updateOffset(offsetAnnot, offsetEOF, -lengthEOF);
offsetSig = updateOffset(offsetSig, offsetEOF, -lengthEOF); offsetSig = updateOffset(offsetSig, offsetEOF, -lengthEOF);
} }
updateXrefBlocks(xrefBlocks, xrefBlocks[i].start, length); updateXrefBlocks(xrefBlocks, xrefBlocks[i].start, length);
offsetAnnot = updateOffset(offsetAnnot, xrefBlocks[i].start, length); offsetAnnot = updateOffset(offsetAnnot, xrefBlocks[i].start, length);
offsetSig = updateOffset(offsetSig, xrefBlocks[i].start, length); offsetSig = updateOffset(offsetSig, xrefBlocks[i].start, length);
} }
const sha256Hex = await sha256(array); var sha256Hex = await sha256(array);
//add the new entries to the xref //add the new entries to the xref
pdf.xref.entries[annotEntry] = {offset: offsetAnnot, pdf.xref.entries[annotEntry] = {offset:offsetAnnot, gen:0, free:false};
gen: 0, pdf.xref.entries[sigEntry] = {offset:offsetSig, gen:0, free:false};
free: false};
pdf.xref.entries[sigEntry] = {offset: offsetSig, var xrefTable = createXrefTable(pdf.xref.entries);
gen: 0, //also empty entries count as in the PDF spec, page 720 (example)
free: false}; xrefTable += createTrailer(pdf.xref.topDict, array.length, sha256Hex, pdf.xref.entries.length);
array = insertIntoArray(array, array.length, xrefTable);
let xrefTable = createXrefTable(pdf.xref.entries);
//also empty entries count as in the PDF spec, page 720 (example) //since we consolidate, no prev! [adjust /Prev -> rawparsing + offset]
xrefTable += createTrailer(pdf.xref.topDict, array.length, sha256Hex, pdf.xref.entries.length); var from1 = 0;
array = insertIntoArray(array, array.length, xrefTable); var to1 = offsetSig+start.length;
var from2 = to1 + crypto.length;
//since we consolidate, no prev! [adjust /Prev -> rawparsing + offset] var to2 = (array.length - from2) - 1;
const from1 = 0; var byteRange = '['+pad10(from1)+' '+pad10(to1 - 1) + ' ' +pad10(from2 + 1)+ ' ' + pad10(to2) + ']';
const to1 = offsetSig + start.length; array = updateArray(array, (offsetSig + offsetByteRange), byteRange);
const from2 = to1 + crypto.length; var data = removeFromArray(array, to1 - 1, from2 + 1);
const to2 = (array.length - from2) - 1; var crypto2 = await sign_pki(signingCert, certificateChain, privateKey, data.buffer, date);
byteRange = '[' + pad10(from1) + ' ' + pad10(to1 - 1) + ' ' + pad10(from2 + 1) + ' ' + pad10(to2) + ']'; array = updateArray(array, to1, crypto2);
array = updateArray(array, offsetSig + offsetByteRange, byteRange); return array;
const data = removeFromArray(array, to1 - 1, from2 + 1);
const crypto2 = await signPki(signingCert, certificateChain, privateKey, data.buffer, date);
array = updateArray(array, to1, crypto2);
return array;
} }
async function appendSig(pdf, root, rootSuccessor, date, signingCert, certificateChain, privateKey) { async function appendSig(pdf, root, rootSuccessor, date, signingCert, certificateChain, privateKey) {
//copy root and the entry with contents to the end //copy root and the entry with contents to the end
const startRoot = pdf.stream.bytes.length + 1; var startRoot = pdf.stream.bytes.length + 1;
let array = copyToEnd(pdf.stream.bytes, root.offset - 1, rootSuccessor.offset); var array = copyToEnd(pdf.stream.bytes, root.offset - 1, rootSuccessor.offset);
//since we signed the first one, we know how the pdf has to look like: //since we signed the first one, we know how the pdf has to look like:
const offsetAcroForm = find(array, '/AcroForm<</Fields', startRoot); var offsetAcroForm = find(array, '/AcroForm<</Fields', startRoot);
const endOffsetAcroForm = find(array, ']', offsetAcroForm); var endOffsetAcroForm = find(array, ']', offsetAcroForm);
const annotEntry = findFreeXrefNr(pdf.xref.entries); var annotEntry = findFreeXrefNr(pdf.xref.entries);
const sigEntry = findFreeXrefNr(pdf.xref.entries, [annotEntry]); var sigEntry = findFreeXrefNr(pdf.xref.entries, [annotEntry]);
const appendAnnot = ' ' + annotEntry + ' 0 R'; var appendAnnot = ' ' + annotEntry + ' 0 R';
array = insertIntoArray(array, endOffsetAcroForm, appendAnnot); array = insertIntoArray(array, endOffsetAcroForm, appendAnnot);
//we need to add Annots [x y R] to the /Type /Page section. We can do that by searching /Annots //we need to add Annots [x y R] to the /Type /Page section. We can do that by searching /Annots
const pages = pdf.catalog.catDict.get('Pages'); var pages = pdf.catalog.catDict.get('Pages');
//get first page, we have hidden sig, so don't bother //get first page, we have hidden sig, so don't bother
const contentRef = pages.get('Kids')[0]; var contentRef = pages.get('Kids')[0];
const xref = pdf.xref.fetch(contentRef); var xref = pdf.xref.fetch(contentRef);
const offsetAnnotEnd = xref.get('#Annots_offset'); var offsetAnnotEnd = xref.get('#Annots_offset');
//we now search ], this is safe as we signed it previously //we now search ], this is safe as we signed it previously
const endOffsetAnnot = find(array, ']', offsetAnnotEnd); var endOffsetAnnot = find(array, ']', offsetAnnotEnd);
const xrefEntry = pdf.xref.getEntry(contentRef.num); var xrefEntry = pdf.xref.getEntry(contentRef.num);
const xrefEntrySuccosser = findSuccessorEntry(pdf.xref.entries, xrefEntry); var xrefEntrySuccosser = findSuccessorEntry(pdf.xref.entries, xrefEntry);
const offsetAnnotRelative = endOffsetAnnot - xrefEntrySuccosser.offset; var offsetAnnotRelative = endOffsetAnnot - xrefEntrySuccosser.offset;
const startContent = array.length; var startContent = array.length;
array = copyToEnd(array, xrefEntry.offset, xrefEntrySuccosser.offset); array = copyToEnd(array, xrefEntry.offset, xrefEntrySuccosser.offset);
array = insertIntoArray(array, array.length + offsetAnnotRelative, appendAnnot); array = insertIntoArray(array, array.length + offsetAnnotRelative, appendAnnot);
const startAnnot = array.length; var startAnnot = array.length;
const append = annotEntry + ' 0 obj\n<</F 132/Type/Annot/Subtype/Widget/Rect[0 0 0 0]/FT/Sig/DR<<>>/T(signature' + annotEntry + ')/V ' + sigEntry + ' 0 R>>\nendobj\n\n'; var append = annotEntry + ' 0 obj\n<</F 132/Type/Annot/Subtype/Widget/Rect[0 0 0 0]/FT/Sig/DR<<>>/T(signature'+annotEntry+')/V '+sigEntry+' 0 R>>\nendobj\n\n';
array = insertIntoArray(array, startAnnot, append); array = insertIntoArray(array, startAnnot, append);
const startSig = array.length; var startSig = array.length;
const start = sigEntry + ' 0 obj\n<</Contents <'; var start = sigEntry+ ' 0 obj\n<</Contents <';
const dummy = await signPki(signingCert, certificateChain, privateKey, stringToUint8Array('A'), date); var dummy = await sign_pki(signingCert, certificateChain, privateKey, stringToUint8Array('A'), date);
//TODO: Adobe thinks its important to have the right size, no idea why this is the case //TODO: Adobe thinks its important to have the right size, no idea why this is the case
const crypto = new Array(round256(dummy.length * 2)).join('0'); var crypto = new Array(round256(dummy.length * 2)).join( '0' );
const middle = '>\n/Type/Sig/SubFilter/adbe.pkcs7.detached/Location()/M(D:' + now(date) + '\')\n/ByteRange '; var middle = '>\n/Type/Sig/SubFilter/adbe.pkcs7.detached/Location()/M(D:'+now(date)+'\')\n/ByteRange ';
let byteRange = '[0000000000 0000000000 0000000000 0000000000]'; var byteRange = '[0000000000 0000000000 0000000000 0000000000]';
const end = '/Filter/Adobe.PPKLite/Reason()/ContactInfo()>>\nendobj\n\n'; var end = '/Filter/Adobe.PPKLite/Reason()/ContactInfo()>>\nendobj\n\n';
//all together //all together
const append2 = start + crypto + middle + byteRange + end; var append2 = start+crypto+middle+byteRange+end;
array = insertIntoArray(array, startSig, append2); array = insertIntoArray(array, startSig, append2);
const sha256Hex = await sha256(array); var sha256Hex = await sha256(array);
const prev = pdf.xref.xrefBlocks[0]; var prev = pdf.xref.xrefBlocks[0];
const startxref = array.length; var startxref = array.length;
const xrefEntries = []; var xrefEntries = [];
xrefEntries[0] = {offset: 0, xrefEntries[0] = {offset:0, gen:65535, free:true};
gen: 65535, xrefEntries[pdf.xref.topDict.getRaw('Root').num] = {offset:startRoot, gen:0, free:false};
free: true}; xrefEntries[contentRef.num] = {offset:startContent, gen:0, free:false};
xrefEntries[pdf.xref.topDict.getRaw('Root').num] = {offset: startRoot, xrefEntries[annotEntry] = {offset:startAnnot, gen:0, free:false};
gen: 0, xrefEntries[sigEntry] = {offset:startSig, gen:0, free:false};
free: false}; var xrefTable = createXrefTableAppend(xrefEntries);
xrefEntries[contentRef.num] = {offset: startContent, xrefTable += createTrailer(pdf.xref.topDict, startxref, sha256Hex, xrefEntries.length, prev);
gen: 0, array = insertIntoArray(array, array.length, xrefTable);
free: false};
xrefEntries[annotEntry] = {offset: startAnnot, var from1 = 0;
gen: 0, var to1 = startSig + start.length;
free: false}; var from2 = to1 + crypto.length;
xrefEntries[sigEntry] = {offset: startSig, var to2 = (array.length - from2) - 1;
gen: 0, var byteRange = '['+pad10(from1)+' '+pad10(to1 - 1) + ' ' +pad10(from2 + 1)+ ' ' + pad10(to2) + ']';
free: false};
let xrefTable = createXrefTableAppend(xrefEntries); array = updateArray(array, from2 + middle.length, byteRange);
xrefTable += createTrailer(pdf.xref.topDict, startxref, sha256Hex, xrefEntries.length, prev); //now sign from1-to1 / from2-to2 and update byterange
array = insertIntoArray(array, array.length, xrefTable);
var data = removeFromArray(array, to1 - 1, from2 + 1);
const from1 = 0; var crypto2 = await sign_pki(signingCert, certificateChain, privateKey, data.buffer, date);
const to1 = startSig + start.length; array = updateArray(array, to1, crypto2);
const from2 = to1 + crypto.length; return array;
const to2 = (array.length - from2) - 1;
byteRange = '[' + pad10(from1) + ' ' + pad10(to1 - 1) + ' ' + pad10(from2 + 1) + ' ' + pad10(to2) + ']';
array = updateArray(array, from2 + middle.length, byteRange);
//now sign from1-to1 / from2-to2 and update byterange
const data = removeFromArray(array, to1 - 1, from2 + 1);
const crypto2 = await signPki(signingCert, certificateChain, privateKey, data.buffer, date);
array = updateArray(array, to1, crypto2);
return array;
} }
function loadPdf(pdfArray) { function loadPdf(pdfArray) {
const pdf = new pdfjsCoreDocument.PDFDocument(false, pdfArray, ''); var pdf = new pdfjsCoreDocument.PDFDocument(false, pdfArray, '');
pdf.parseStartXRef(); pdf.parseStartXRef();
pdf.parse(); pdf.parse();
return pdf; return pdf;
} }
//data must be Uint8Array //data must be Uint8Array
async function signPki(signingCert, certificateChain, privateKey, data, date) { async function sign_pki(signingCert, certificateChain, privateKey, data, date) {
const crypto = getCrypto();
const crypto = getCrypto();
//date = typeof date !== 'undefined' ? date : new Date();
//date = typeof date !== 'undefined' ? date : new Date();
const hashAlg = "SHA-256";
const hashAlg = "SHA-256";
const digest = await crypto.digest({ name: hashAlg }, data);
const digest = await crypto.digest({ name: hashAlg }, data);
const signedAttr = [];
const signedAttr = [];
signedAttr.push(new Attribute({
type: "1.2.840.113549.1.9.3", signedAttr.push(new Attribute({
values: [ type: "1.2.840.113549.1.9.3",
new ObjectIdentifier({ value: "1.2.840.113549.1.7.1" }) values: [
] new ObjectIdentifier({ value: "1.2.840.113549.1.7.1" })
})); // contentType ]
})); // contentType
signedAttr.push(new Attribute({
type: "1.2.840.113549.1.9.4", signedAttr.push(new Attribute({
values: [ type: "1.2.840.113549.1.9.4",
new OctetString({ valueHex: digest }) values: [
] new OctetString({ valueHex: digest })
})); // messageDigest ]
})); // messageDigest
signedAttr.push(new Attribute({
type: "1.2.840.113549.1.9.5", signedAttr.push(new Attribute({
values: [ type: "1.2.840.113549.1.9.5",
new UTCTime({ valueDate: date }) values: [
] new UTCTime({ valueDate: date })
})); // signingTime ]
})); // signingTime
const cmsSignedSimpl = new SignedData({
version: 1, const cmsSignedSimpl = new SignedData({
encapContentInfo: new EncapsulatedContentInfo({
eContentType: "1.2.840.113549.1.7.1" // "data" content type
}),
signerInfos: [
new SignerInfo({
version: 1, version: 1,
sid: new IssuerAndSerialNumber({ encapContentInfo: new EncapsulatedContentInfo({
issuer: signingCert.issuer, eContentType: "1.2.840.113549.1.7.1" // "data" content type
serialNumber: signingCert.serialNumber
}), }),
signedAttrs: new SignedAndUnsignedAttributes({ signerInfos: [
type: 0, new SignerInfo({
attributes: signedAttr version: 1,
}) sid: new IssuerAndSerialNumber({
}) issuer: signingCert.issuer,
], serialNumber: signingCert.serialNumber
certificates: certificateChain }),
}); signedAttrs: new SignedAndUnsignedAttributes({
type: 0,
attributes: signedAttr
})
})
],
certificates: certificateChain
});
await cmsSignedSimpl.sign(privateKey, 0, hashAlg, data.buffer); const signatureBuffer = await cmsSignedSimpl.sign(privateKey, 0, hashAlg, data.buffer);
const cmsSignedSchema = cmsSignedSimpl.toSchema(true); const cmsSignedSchema = cmsSignedSimpl.toSchema(true);
const cmsContentSimp = new ContentInfo({ const cmsContentSimp = new ContentInfo({
contentType: "1.2.840.113549.1.7.2", contentType: "1.2.840.113549.1.7.2",
content: cmsSignedSchema content: cmsSignedSchema
}); });
const _cmsSignedSchema = cmsContentSimp.toSchema(); const _cmsSignedSchema = cmsContentSimp.toSchema();
//region Make length of some elements in "indefinite form" //region Make length of some elements in "indefinite form"
_cmsSignedSchema.lenBlock.isIndefiniteForm = true; _cmsSignedSchema.lenBlock.isIndefiniteForm = true;
const block1 = _cmsSignedSchema.valueBlock.value[1]; const block1 = _cmsSignedSchema.valueBlock.value[1];
block1.lenBlock.isIndefiniteForm = true; block1.lenBlock.isIndefiniteForm = true;
const block2 = block1.valueBlock.value[0]; const block2 = block1.valueBlock.value[0];
block2.lenBlock.isIndefiniteForm = true; block2.lenBlock.isIndefiniteForm = true;
//endregion //endregion
const cmsSignedBuffer = _cmsSignedSchema.toBER(false); let cmsSignedBuffer = _cmsSignedSchema.toBER(false);
const cmsSignedArray = new Uint8Array(cmsSignedBuffer); const cmsSignedArray = new Uint8Array(cmsSignedBuffer);
const cmsSignedString = uint8ArrayToString(cmsSignedArray); const cmsSignedString = uint8ArrayToString(cmsSignedArray);
const hex = strHex(cmsSignedString); const hex = strHex(cmsSignedString);
return hex; return hex;
} }
async function signPdfObjects(pdfRaw, signingCert, certificateChain, privateKey, date) {
date = typeof date !== 'undefined' ? date : new Date(); async function signPdfObjects (pdfRaw, signingCert, certificateChain, privateKey, date) {
if (pdfRaw instanceof ArrayBuffer) { date = typeof date !== 'undefined' ? date : new Date();
pdfRaw = new Uint8Array(pdfRaw); if(pdfRaw instanceof ArrayBuffer) {
} pdfRaw = new Uint8Array(pdfRaw);
const pdf = loadPdf(pdfRaw); }
const root = findRootEntry(pdf.xref); var pdf = loadPdf(pdfRaw);
const rootSuccessor = findSuccessorEntry(pdf.xref.entries, root); var root = findRootEntry(pdf.xref);
if (!isSigInRoot(pdf)) { var rootSuccessor = findSuccessorEntry(pdf.xref.entries, root);
return await newSig(pdf, root, rootSuccessor, date, signingCert, certificateChain, privateKey); if(!isSigInRoot(pdf)) {
} else { return await newSig(pdf, root, rootSuccessor, date, signingCert, certificateChain, privateKey);
return await appendSig(pdf, root, rootSuccessor, date, signingCert, certificateChain, privateKey); } else {
} return await appendSig(pdf, root, rootSuccessor, date, signingCert, certificateChain, privateKey);
}
} }
export function signPdf(pdfRaw, signingCert, certificateChain, privateKey) { export function signPdf(pdfRaw, signingCert, certificateChain, privateKey) {
const signingCertObj = parseCertificate(signingCert); const signingCertObj = parseCertificate(signingCert);
const certificateChainObj = []; const certificateChainObj = [];
certificateChainObj[0] = parseCertificate(signingCert); certificateChainObj[0] = parseCertificate(signingCert);
for (let i = 0; i < certificateChain.length; i++) { for (let i = 0; i < certificateChain.length; i++) {
certificateChainObj[i + 1] = parseCertificate(certificateChain[i]); certificateChainObj[i + 1] = parseCertificate(certificateChain[i])
} }
return parsePrivateKey(privateKey).then(privateKeyDecoded => { return parsePrivateKey(privateKey).then(privateKeyDecoded => {
return signPdfObjects(pdfRaw, signingCertObj, certificateChainObj, privateKeyDecoded); return signPdfObjects(pdfRaw, signingCertObj, certificateChainObj, privateKeyDecoded);
}); });
} }
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment