@syncfusion/ej2-pdf
Version:
Feature-rich JavaScript PDF library with built-in support for loading and manipulating PDF document.
926 lines (925 loc) • 45.2 kB
JavaScript
import { _extractAttributes, _areUint8ArraysEqual, _bytesToHex, _padStart } from '../../utils';
import { _PdfBigInt } from './pdf-big-integer';
import { _PdfCertificateIdentifier } from './pdf-certificate-identifier';
import { _PdfCertificateTable } from './pdf-certificate-table';
import { _PdfSubjectKeyIdentifier } from './pdf-key-identifier';
import { _PdfPublicKeyInformation } from './x509/x509-certificate-key';
import { _PdfAlgorithms } from './x509/x509-algorithm';
import { _PdfUniqueBitString } from './x509/x509-bit-string-handler';
import { _PdfX509Certificates } from './x509/x509-certificate';
import { _PdfX509CertificateParser } from './x509/x509-certificate-parser';
import { _PdfRonCipherParameter } from './x509/x509-cipher-handler';
import { _PdfObjectIdentifier } from './asn1/identifier-mapping';
import { _PdfUniqueEncodingElement } from './asn1/unique-encoding-element';
import { _PdfBasicEncodingElement } from './asn1/basic-encoding-element';
import { _isBasicEncodingElement } from './asn1/utils';
import { _TagClassType } from './asn1/enumerator';
import { _Sha1 } from '../encryptors/secureHash-algorithm1';
//import { _Sha256 } from '../encryptors/secureHash-algorithm256';
//import { _Sha384, _Sha512 } from '../encryptors/secureHash-algorithm512';
import { _MD5 } from '../encryptors/messageDigest5';
//import { _RaceEvaluationMessageDigest } from '../encryptors/evaluation-digest';
import { _AdvancedEncryption128Cipher } from '../encryptors/advance-cipher';
import { _CipherTwo, _NormalCipherFour } from '../encryptors/normal-cipher';
import { _TripleDataEncryptionStandardCipher } from '../encryptors/encryption-cipher';
import { _DataEncryptionStandardCipher } from '../encryptors/cipher-tranform';
/**
* PKCS#7 / PKCS#12 certificate and key container helper with parsing and extraction utilities.
*
* @private
*/
var _PdfPublicKeyCryptographyCertificate = /** @class */ (function () {
function _PdfPublicKeyCryptographyCertificate(input, password) {
/**
* Raw ASN.1 certificate chain elements extracted from the container.
*
* @private
* @type {_PdfAbstractSyntaxElement[]}
*/
this._certificateChain = [];
/**
* Map of key identifiers/names to key entries or private key structures.
*
* @private
* @type {Map<string, any>}
*/
this._keys = new Map(); //eslint-disable-line
/**
* Mapping of local identifier strings to hex key names.
*
* @private
* @type {Map<string,string>}
*/
this._localIdentifiers = new Map();
/**
* OID for data content type.
*
* @private
* @type {string}
*/
this._data = '1.2.840.113549.1.7.1';
/**
* OID for encrypted data content type.
*
* @private
* @type {string}
*/
this._encryptedData = '1.2.840.113549.1.7.6';
/**
* OID for certificate bag in PKCS#12.
*
* @private
* @type {string}
*/
this._certificateBag = '1.2.840.113549.1.12.10.1.3';
/**
* OID for shroudedKeyBag in PKCS#12.
*
* @private
* @type {string}
*/
this._shroudedKeyBag = '1.2.840.113549.1.12.10.1.2';
/**
* OID for keyBag in PKCS#12.
*
* @private
* @type {string}
*/
this._keyBag = '1.2.840.113549.1.12.10.1.1';
/**
* Attributes parsed from the container metadata.
*
* @private
* @type {Record<string, any>}
*/
this._attributes = {}; //eslint-disable-line
/**
* Table of named certificates (used for lookup by friendly name).
*
* @private
* @type {_PdfCertificateTable}
*/
this._certificates = new _PdfCertificateTable();
/**
* True when a private key was encountered without a local identifier.
*
* @private
* @type {boolean}
*/
this._isUnMarkedKey = false;
if (input && input.length > 0 && password !== null) {
this._loadCertificate(input, password);
}
}
/**
* Create a subject key identifier helper from the provided public key parameters.
*
* @private
* @param {_PdfCipherParameter} publicKey - Parsed public key parameters.
* @param {Uint8Array} id - Raw key identifier bytes.
* @returns {_PdfSubjectKeyIdentifier} Constructed subject key identifier helper.
*/
_PdfPublicKeyCryptographyCertificate.prototype._createSubjectKeyID = function (publicKey, id) {
if (publicKey instanceof _PdfRonCipherParameter) {
var algorithm = new _PdfAlgorithms();
algorithm._objectID = new _PdfObjectIdentifier()._fromString('1.2.840.113549.1.1.1');
algorithm._parameters = algorithm._getUniqueEncoderNull();
algorithm._parametersDefined = true;
var bitString = new _PdfUniqueBitString(id, 0);
var publicKeyInfo = new _PdfPublicKeyInformation(algorithm, bitString);
return new _PdfSubjectKeyIdentifier(publicKeyInfo);
}
throw new Error("Invalid Key: " + publicKey);
};
/**
* Load and parse a PKCS container (PFX/P12) from bytes using the provided password.
*
* @private
* @param {Uint8Array} input - The container bytes.
* @param {string} password - Password to decrypt the container.
* @returns {void}
*/
_PdfPublicKeyCryptographyCertificate.prototype._loadCertificate = function (input, password) {
if (!input || input.length === 0) {
throw new Error('input is null');
}
if (!password) {
throw new Error('password is null');
}
var root = new _PdfUniqueEncodingElement();
root._fromBytes(input);
var pfxSequence = root._getSequence();
var contentInfo = pfxSequence[1];
var contentInfoSeq = contentInfo._getSequence();
var taggedContent = contentInfoSeq[1];
var seq = taggedContent._getSequence();
var contentOctetElement = seq && seq[0];
if (!contentOctetElement || !contentOctetElement._getOctetString()) {
throw new Error('Missing or invalid content octets');
}
var contentOctets = contentOctetElement._getOctetString();
var innerIsBER = _isBasicEncodingElement(contentOctets);
var inner = innerIsBER ? new _PdfBasicEncodingElement() : new _PdfUniqueEncodingElement();
inner._fromBytes(contentOctets);
var innerSequence = inner._getSequence();
for (var _i = 0, innerSequence_1 = innerSequence; _i < innerSequence_1.length; _i++) {
var entry = innerSequence_1[_i];
var entrySeq = entry._getSequence();
var typeOID = entrySeq[0]._getObjectIdentifier().toString();
if (typeOID === this._data) {
var dataContentWrapper = entrySeq[1];
var dataContent = dataContentWrapper._getSequence()
&& dataContentWrapper._getSequence()[0];
if (dataContent) {
this._processData(dataContent, password);
}
}
else if (typeOID === this._encryptedData) {
var encryptedContentWrapper = entrySeq[1];
var dataContent = encryptedContentWrapper._getSequence()
? encryptedContentWrapper._getSequence()[0]
: undefined;
this._processEncryptedData(dataContent, password);
}
}
if (this._certificateChain && this._certificateChain.length > 0) {
this._processCertificateCollection(this._certificateChain);
}
};
/**
* Process and index a collection of ASN.1 certificate entries extracted from the container.
*
* @private
* @param {any[]} certificateChain - Array of ASN.1 certificate elements.
* @returns {void}
*/
_PdfPublicKeyCryptographyCertificate.prototype._processCertificateCollection = function (certificateChain) {
this._certificates = new _PdfCertificateTable();
this._chainCertificates = new Map();
this._keyCertificates = new Map();
for (var _i = 0, certificateChain_1 = certificateChain; _i < certificateChain_1.length; _i++) {
var abstractSyntaxCollection = certificateChain_1[_i];
var asn1Sequence = abstractSyntaxCollection;
var sequence = asn1Sequence._getSequence();
var certValue = sequence[1];
var certSequence = certValue._getSequence();
var certOctet = certSequence[0]._getSequence()[1]._getSequence()[0]._getValue();
if (!certOctet) {
continue;
}
var certificate = new _PdfX509CertificateParser()._readCertificate(certOctet);
if (!certificate) {
continue;
}
var attributes = {}; // eslint-disable-line
var localId = void 0;
var key = void 0;
var tempAttributes = _extractAttributes(asn1Sequence);
if (tempAttributes) {
var attributeSet = void 0;
try {
if (tempAttributes) {
attributeSet = tempAttributes._getAbstractSetValue();
}
}
catch (_a) {
if (tempAttributes) {
attributeSet = tempAttributes._getSequence();
}
}
for (var _b = 0, attributeSet_1 = attributeSet; _b < attributeSet_1.length; _b++) {
var sequence_1 = attributeSet_1[_b];
var items = sequence_1._getSequence();
if (!items || items.length < 2) {
continue;
}
var attributeOid = items[0]._getObjectIdentifier().toString();
var attrSet = typeof items[1]._getAbstractSetValue() !== 'undefined' &&
items[1]._getAbstractSetValue() !== null
? items[1]._getAbstractSetValue()
: items[1]._getSequence();
if (!attrSet || attrSet.length === 0) {
continue;
}
var attr = attrSet[0];
if (attributes[attributeOid]) {
if (JSON.stringify(attributes[attributeOid]) !== JSON.stringify(attr)) {
throw new Error('attempt to add existing attribute with different value');
}
}
else {
attributes[attributeOid] = attr;
}
if (attributeOid === '1.2.840.113549.1.9.20') {
key = attr._getBmpString();
}
else if (attributeOid === '1.2.840.113549.1.9.21') {
localId = attr._getOctetString();
}
}
}
var certId = new _PdfCertificateIdentifier({ pubicKey: certificate._getPublicKey(),
id: certificate._publicKeyBytes });
var certificateCollection = new _PdfX509Certificates(certificate);
this._chainCertificates.set(certId, certificateCollection);
if (this._isUnMarkedKey) {
var name_1 = _bytesToHex(certId._identifier);
this._keyCertificates.set(name_1, certificateCollection);
var temp = this._keys.get('unmarked');
this._keys.delete('unmarked');
this._keys.set('name', temp);
}
else {
if (localId) {
var name_2 = _bytesToHex(localId);
this._keyCertificates.set(name_2, certificateCollection);
}
if (key) {
this._certificates._setValue(key, certificateCollection);
}
}
}
};
/**
* Process a PKCS Data content element, extracting keys and certificates.
*
* @private
* @param {_PdfAbstractSyntaxElement} contentElement - ASN.1 content element.
* @param {string} password - Password for encrypted entries.
* @returns {void}
*/
_PdfPublicKeyCryptographyCertificate.prototype._processData = function (contentElement, password) {
var octets = contentElement._getOctetString();
if (!octets) {
return;
}
var innerIsBER = _isBasicEncodingElement(octets);
var inner = innerIsBER ? new _PdfBasicEncodingElement() : new _PdfUniqueEncodingElement();
inner._fromBytes(octets);
var contentSequence = inner._getSequence();
for (var _i = 0, contentSequence_1 = contentSequence; _i < contentSequence_1.length; _i++) {
var sub = contentSequence_1[_i];
var subSeq = sub._getSequence();
var bagId = subSeq[0]._getObjectIdentifier().toString();
if (bagId === '1.2.840.113549.1.12.10.1.2') {
var encryptedKeyOctets = subSeq[1]._getSequence()[0];
var encryptedKeyInfoSeq = encryptedKeyOctets._getSequence();
var encryptionAlgorithmSeq = encryptedKeyInfoSeq[0]._getSequence();
var encryptedOctets = encryptedKeyInfoSeq[1]._getOctetString();
var decryptedKeyBytes = this._getCryptographicData(encryptionAlgorithmSeq, encryptedOctets, password);
var innerIsBER_1 = _isBasicEncodingElement(octets);
var privateKeyElement = innerIsBER_1 ? new _PdfBasicEncodingElement() :
new _PdfUniqueEncodingElement();
privateKeyElement._fromBytes(decryptedKeyBytes);
var keySeq = privateKeyElement._getSequence();
var algorithmOID = keySeq[1]._getSequence()[0]._getObjectIdentifier().toString();
var privateKeyOctets = keySeq[2]._getOctetString();
var privateKey = void 0; //eslint-disable-line
if (algorithmOID === '1.2.840.113549.1.1.1') {
var parsed = this._parsePrivateKey(privateKeyOctets); // eslint-disable-line
privateKey = this._createPrivateKey(parsed.modulus, parsed.publicExponent, parsed.privateExponent, parsed.prime1, parsed.prime2, parsed.exponent1, parsed.exponent2, parsed.coefficient);
}
var localIdentifier = void 0;
var localId = void 0;
var attributes = {}; //eslint-disable-line
var keyEntry = void 0;
if (privateKey) {
keyEntry = {
privateKey: privateKey,
attributes: attributes
};
}
var attributeSequence = (subSeq[2] && subSeq[2]._getSequence()
? subSeq[2]._getSequence()
: []).map(function (el) { return el; });
if (attributeSequence && attributeSequence.length > 0) {
for (var _a = 0, attributeSequence_1 = attributeSequence; _a < attributeSequence_1.length; _a++) {
var attribute = attributeSequence_1[_a];
var attributeSet = attribute._getSequence();
var attributeOid = attributeSet[0]._getObjectIdentifier().toString();
var attributeValues = attributeSet[1]._getAbstractSetValue();
if (attributeValues && attributeValues.length > 0) {
var value = attributeValues[0];
if (attributes[attributeOid] && attributes[attributeOid] !== value) {
throw new Error('Should not add existing attribute with different value');
}
attributes[attributeOid] = value;
if (attributeOid === '1.2.840.113549.1.9.20') {
localIdentifier = value._getBmpString() ? value._getBmpString()
: value._getUtf8String() ? value._getUtf8String() : '';
}
else if (attributeOid === '1.2.840.113549.1.9.21') {
localId = value._getOctetString();
}
}
}
}
if (localId) {
var name_3 = Array.from(localId)
.map(function (b) { return _padStart(b.toString(16), 2, '0'); })
.join('');
if (!localIdentifier) {
this._keys.set(name_3, keyEntry);
}
else {
this._localIdentifiers.set(localIdentifier, name_3);
this._keys.set(localIdentifier, keyEntry);
}
}
else {
this._isUnMarkedKey = true;
this._keys.set('unmarked', privateKey);
}
}
else if (bagId === this._certificateBag) {
this._certificateChain.push(sub);
}
}
};
_PdfPublicKeyCryptographyCertificate.prototype._parseAndDecrypt = function (contentElement, password) {
var encryptedDataSeq = contentElement._getSequence();
var encryptedContentInfo = encryptedDataSeq[1]._getSequence();
var encryptionAlgorithm = encryptedContentInfo[1]._getSequence();
var encryptedOctet = encryptedContentInfo[2]._getOctetString();
return this._getCryptographicData(encryptionAlgorithm, encryptedOctet, password);
};
_PdfPublicKeyCryptographyCertificate.prototype._decodeDecryptedBytes = function (decryptedBytes) {
var innerIsBER = _isBasicEncodingElement(decryptedBytes);
var decryptedElement = innerIsBER ? new _PdfBasicEncodingElement() : new _PdfUniqueEncodingElement();
decryptedElement._fromBytes(decryptedBytes);
return decryptedElement._getSequence();
};
_PdfPublicKeyCryptographyCertificate.prototype._handleCertificateBag = function (cert) {
this._certificateChain.push(cert);
};
_PdfPublicKeyCryptographyCertificate.prototype._extractPrivateKeyFromKeyInfo = function (keyInfoRoot, password, isEncrypted) {
if (isEncrypted) {
// certSeq[1]._getSequence()[0] => EncryptedPrivateKeyInfo (for shroudedKeyBag)
var encryptedPrivateKeyInfo = keyInfoRoot._getSequence()[0];
var encryptedKeyInfoSeq = encryptedPrivateKeyInfo._getSequence();
var encryptionAlgorithmSeq = encryptedKeyInfoSeq[0]._getSequence();
var encryptedPrivOctets = encryptedKeyInfoSeq[1]._getOctetString();
var decryptedKeyBytes = this._getCryptographicData(encryptionAlgorithmSeq, encryptedPrivOctets, password);
var innerIsBER = _isBasicEncodingElement(decryptedKeyBytes);
var privKeyElement = innerIsBER ? new _PdfBasicEncodingElement() : new _PdfUniqueEncodingElement();
privKeyElement._fromBytes(decryptedKeyBytes);
var keySeq = privKeyElement._getSequence();
var algorithmOID = keySeq[1]._getSequence()[0]._getObjectIdentifier().toString();
var privateKeyOctets = keySeq[2]._getOctetString();
var privateKey = void 0; // eslint-disable-line
if (algorithmOID === '1.2.840.113549.1.1.1') {
var parsed = this._parsePrivateKey(privateKeyOctets);
privateKey = this._createPrivateKey(parsed.modulus, parsed.publicExponent, parsed.privateExponent, parsed.prime1, parsed.prime2, parsed.exponent1, parsed.exponent2, parsed.coefficient);
}
return { privateKey: privateKey, attributesRoot: null };
}
else {
var privKeyInfoElement = keyInfoRoot._getSequence()[0];
var keyInfoSeq = privKeyInfoElement._getSequence();
var algorithmOID = keyInfoSeq[1]._getSequence()[0]._getObjectIdentifier().toString();
var privateKeyOctets = keyInfoSeq[2]._getOctetString();
var privateKey = void 0; // eslint-disable-line
if (algorithmOID === '1.2.840.113549.1.1.1') {
var parsed = this._parsePrivateKey(privateKeyOctets); // eslint-disable-line
privateKey = this._createPrivateKey(parsed.modulus, parsed.publicExponent, parsed.privateExponent, parsed.prime1, parsed.prime2, parsed.exponent1, parsed.exponent2, parsed.coefficient);
}
return { privateKey: privateKey, attributesRoot: null };
}
};
_PdfPublicKeyCryptographyCertificate.prototype._extractLocalIdentifiers = function (attrsContainer) {
var localIdentifier;
var localId;
var attributeSequence = (attrsContainer && attrsContainer._getSequence()
? attrsContainer._getSequence()
: []).map(function (el) { return el; });
for (var _i = 0, attributeSequence_2 = attributeSequence; _i < attributeSequence_2.length; _i++) {
var attribute = attributeSequence_2[_i];
var attributeSet = attribute._getSequence();
var attributeOid = attributeSet[0]._getObjectIdentifier().toString();
var attributeValues = attributeSet[1]._getAbstractSetValue();
if (attributeValues.length > 0) {
var value = attributeValues[0];
if (attributeOid === '1.2.840.113549.1.9.20') {
localIdentifier = value._getBmpString() ? value._getBmpString() : (value._getUtf8String() ? value._getUtf8String() : '');
}
else if (attributeOid === '1.2.840.113549.1.9.21') {
localId = value._getOctetString();
}
}
}
return { localIdentifier: localIdentifier, localId: localId };
};
_PdfPublicKeyCryptographyCertificate.prototype._storeKeyEntry = function (localIdentifier, localId, keyEntry) {
if (localId) {
var name_4 = Array.from(localId).map(function (b) { return _padStart(b.toString(16), 2, '0'); }).join('');
if (!localIdentifier) {
this._keys.set(name_4, keyEntry);
}
else {
this._localIdentifiers.set(localIdentifier, name_4);
this._keys.set(localIdentifier, keyEntry);
}
}
else {
this._keys.set('unmarked', keyEntry);
}
};
_PdfPublicKeyCryptographyCertificate.prototype._handleShroudedKeyBag = function (certSeq, password) {
var encryptedPrivateKeyInfo = certSeq[1]._getSequence()[0];
var encryptedKeyInfoSeq = encryptedPrivateKeyInfo._getSequence();
var encryptionAlgorithmSeq = encryptedKeyInfoSeq[0]._getSequence();
var encryptedPrivOctets = encryptedKeyInfoSeq[1]._getOctetString();
var decryptedKeyBytes = this._getCryptographicData(encryptionAlgorithmSeq, encryptedPrivOctets, password);
var innerIsBER = _isBasicEncodingElement(decryptedKeyBytes);
var privKeyElement = innerIsBER ? new _PdfBasicEncodingElement() : new _PdfUniqueEncodingElement();
privKeyElement._fromBytes(decryptedKeyBytes);
var keySeq = privKeyElement._getSequence();
var algorithmOID = keySeq[1]._getSequence()[0]._getObjectIdentifier().toString();
var privateKeyOctets = keySeq[2]._getOctetString();
var privateKey; // eslint-disable-line
if (algorithmOID === '1.2.840.113549.1.1.1') {
var parsed = this._parsePrivateKey(privateKeyOctets);
privateKey = this._createPrivateKey(parsed.modulus, parsed.publicExponent, parsed.privateExponent, parsed.prime1, parsed.prime2, parsed.exponent1, parsed.exponent2, parsed.coefficient);
}
var attributesRoot = certSeq[2];
var _a = this._extractLocalIdentifiers(attributesRoot), localIdentifier = _a.localIdentifier, localId = _a.localId;
if (privateKey) {
var keyEntry = { privateKey: privateKey, attributes: {} };
this._storeKeyEntry(localIdentifier, localId, keyEntry);
}
};
_PdfPublicKeyCryptographyCertificate.prototype._handleKeyBag = function (certSeq) {
var privKeyInfoElement = certSeq[1]._getSequence()[0];
var keyInfoSeq = privKeyInfoElement._getSequence();
var algorithmOID = keyInfoSeq[1]._getSequence()[0]._getObjectIdentifier().toString();
var privateKeyOctets = keyInfoSeq[2]._getOctetString();
var privateKey; // eslint-disable-line
if (algorithmOID === '1.2.840.113549.1.1.1') {
var parsed = this._parsePrivateKey(privateKeyOctets); // eslint-disable-line
privateKey = this._createPrivateKey(parsed.modulus, parsed.publicExponent, parsed.privateExponent, parsed.prime1, parsed.prime2, parsed.exponent1, parsed.exponent2, parsed.coefficient);
}
var attributesRoot = certSeq[2];
var _a = this._extractLocalIdentifiers(attributesRoot), localIdentifier = _a.localIdentifier, localId = _a.localId;
if (privateKey) {
var keyEntry = { privateKey: privateKey, attributes: {} };
this._storeKeyEntry(localIdentifier, localId, keyEntry);
}
};
/**
* Process an EncryptedData content element, dispatching to appropriate handlers.
*
* @private
* @param {_PdfAbstractSyntaxElement} contentElement - EncryptedData ASN.1 element.
* @param {string} password - Password used for decryption.
* @returns {void}
*/
_PdfPublicKeyCryptographyCertificate.prototype._processEncryptedData = function (contentElement, password) {
var decryptedBytes = this._parseAndDecrypt(contentElement, password);
var certSequence = this._decodeDecryptedBytes(decryptedBytes);
for (var _i = 0, certSequence_1 = certSequence; _i < certSequence_1.length; _i++) {
var cert = certSequence_1[_i];
var certSeq = cert._getSequence();
var bagId = certSeq[0]._getObjectIdentifier().toString();
if (bagId === this._certificateBag) {
this._handleCertificateBag(cert);
}
else if (bagId === this._shroudedKeyBag) {
this._handleShroudedKeyBag(certSeq, password);
}
else if (bagId === this._keyBag) {
this._handleKeyBag(certSeq);
}
}
};
/**
* Construct a JavaScript private key object from raw RSA components.
*
* @private
* @param {Uint8Array} modulus - RSA modulus bytes.
* @param {Uint8Array} publicExponent - RSA public exponent bytes.
* @param {Uint8Array} privateExponent - RSA private exponent bytes.
* @param {Uint8Array} p - RSA prime1 bytes.
* @param {Uint8Array} q - RSA prime2 bytes.
* @param {Uint8Array} dP - RSA exponent1 bytes.
* @param {Uint8Array} dQ - RSA exponent2 bytes.
* @param {Uint8Array} inverse - RSA coefficient (qInv) bytes.
* @returns {any} An object representing the private key and accessors.
*/
_PdfPublicKeyCryptographyCertificate.prototype._createPrivateKey = function (modulus, publicExponent, privateExponent, p, q, dP, dQ, inverse) {
var mod = this._uint8ArrayToBigInt(modulus);
var pubExp = this._uint8ArrayToBigInt(publicExponent);
var privExp = this._uint8ArrayToBigInt(privateExponent);
var _p = this._uint8ArrayToBigInt(p);
var _q = this._uint8ArrayToBigInt(q);
var _dP = this._uint8ArrayToBigInt(dP);
var _dQ = this._uint8ArrayToBigInt(dQ);
var inv = this._uint8ArrayToBigInt(inverse);
var _isPrivate = true;
this._validateValue('publicExponent', pubExp);
this._validateValue('p', _p);
this._validateValue('q', _q);
this._validateValue('dP', _dP);
this._validateValue('dQ', _dQ);
this._validateValue('inverse', inv);
return {
modulus: mod,
publicExponent: pubExp,
privateExponent: privExp,
p: _p,
q: _q,
dP: _dP,
dQ: _dQ,
inverse: inv,
get PublicExponent() { return pubExp; },
get P() { return _p; },
get Q() { return _q; },
get DP() { return _dP; },
get DQ() { return _dQ; },
get QInv() { return inv; },
get _isPrivate() { return _isPrivate; },
equals: function (other) {
if (!other) {
return false;
}
return (this.dP === other.dP &&
this.dQ === other.dQ &&
this.privateExponent === other.privateExponent &&
this.modulus === other.modulus &&
this.p === other.p &&
this.q === other.q &&
this.publicExponent === other.publicExponent &&
this.inverse === other.inverse);
},
hashCode: function () {
return (this._extractLow32Bits(this.DP) ^
this._extractLow32Bits(this.DQ) ^
this._extractLow32Bits(this.privateExponent) ^
this._extractLow32Bits(this.modulus) ^
this._extractLow32Bits(this.P) ^
this._extractLow32Bits(this.Q) ^
this._extractLow32Bits(this.PublicExponent) ^
this._extractLow32Bits(this.QInv));
}
};
};
/**
* Validate that an RSA parameter value is present.
*
* @private
* @param {string} name - Parameter name for error messages.
* @param {_PdfBigInt} value - The big integer value to validate.
* @returns {void}
*/
_PdfPublicKeyCryptographyCertificate.prototype._validateValue = function (name, value) {
if (value === null || typeof value === 'undefined') {
throw new Error("RSA parameter '" + name + "' is null or undefined");
}
};
/**
* Convert a Uint8Array containing big-endian bytes into a `_PdfBigInt` helper.
*
* @private
* @param {Uint8Array} bytes - Big-endian byte sequence.
* @returns {_PdfBigInt} The constructed big-integer helper.
*/
_PdfPublicKeyCryptographyCertificate.prototype._uint8ArrayToBigInt = function (bytes) {
var result = new _PdfBigInt('0');
for (var i = 0; i < bytes.length; i++) {
result._multiply();
result._add(bytes[i]);
}
return result;
};
/**
* Encode a UTF-16BE password string into the byte format expected by PKCS#12.
*
* @private
* @param {string} password - Password to encode.
* @returns {Uint8Array} Encoded password bytes.
*/
_PdfPublicKeyCryptographyCertificate.prototype._getPassword = function (password) {
var out = new Uint8Array((password.length + 1) * 2);
for (var i = 0; i < password.length; ++i) {
var code = password.charCodeAt(i);
out[i * 2] = code >> 8;
out[i * 2 + 1] = code & 0xff;
}
return out;
};
/**
* Decrypt encrypted content using the specified algorithm sequence and password.
*
* @private
* @param {_PdfAbstractSyntaxElement[]} algorithmSeq - ASN.1 algorithm parameters sequence.
* @param {Uint8Array} encryptedData - Encrypted payload bytes.
* @param {string} password - Password used to derive keys.
* @returns {Uint8Array} Decrypted bytes.
*/
_PdfPublicKeyCryptographyCertificate.prototype._getCryptographicData = function (algorithmSeq, encryptedData, password) {
var oid = algorithmSeq[0]._getObjectIdentifier().toString();
var params = algorithmSeq[1]._getSequence();
var salt = params[0]._getOctetString();
var iterations = Number(params[1]._getInteger());
var passwordBytes = this._getPassword(password);
var oidMap = {
'1.2.840.113549.1.12.1.1': { name: 'PBEwithSHA-1and128bitRC4', keySize: 16, ivSize: 0, cipher: 'RC4', hash: 'sha1' },
'1.2.840.113549.1.12.1.2': { name: 'PBEwithSHA-1and40bitRC4', keySize: 5, ivSize: 0, cipher: 'RC4', hash: 'sha1' },
'1.2.840.113549.1.12.1.3': { name: 'PBEwithSHA-1and3-KeyTripleDES-CBC', keySize: 24, ivSize: 8, cipher: 'DESEDE', hash: 'sha1' },
'1.2.840.113549.1.12.1.4': { name: 'PBEwithSHA-1and3-KeyTripleDES-CBC', keySize: 24, ivSize: 8, cipher: 'DESEDE', hash: 'sha1' },
'1.2.840.113549.1.12.1.5': { name: 'PBEwithSHA-1and128bitRC2-CBC', keySize: 16, ivSize: 8, cipher: 'RC2', hash: 'sha1' },
'1.2.840.113549.1.12.1.6': { name: 'PBEwithSHA-1and40bitRC2-CBC', keySize: 5, ivSize: 8, cipher: 'RC2', hash: 'sha1' },
'1.2.840.113549.1.5.12': { name: 'PBKDF2', keySize: 0, ivSize: 0, cipher: 'AES', hash: 'sha1' },
'1.2.840.113549.1.5.3': { name: 'pbeWithMD5AndDES-CBC', keySize: 8, ivSize: 8, cipher: 'DES', hash: 'md5' },
'1.2.840.113549.1.5.10': { name: 'pbeWithSHA1AndDES-CBC', keySize: 8, ivSize: 8, cipher: 'DES', hash: 'sha1' },
'1.2.840.113549.1.12.1.8': { name: 'PBEwithSHA-1and128bitRC2-CBC', keySize: 16, ivSize: 8, cipher: 'RC2', hash: 'sha1' },
'1.2.840.113549.1.12.1.9': { name: 'PBEwithSHA-1and40bitRC2-CBC', keySize: 5, ivSize: 8, cipher: 'RC2', hash: 'sha1' },
'1.2.840.113549.1.5.6': { name: 'pbeWithMD5AndRC2-CBC', keySize: 16, ivSize: 8, cipher: 'RC2', hash: 'md5' },
'1.2.840.113549.1.5.11': { name: 'pbeWithSHA1AndRC2-CBC', keySize: 16, ivSize: 8, cipher: 'RC2', hash: 'sha1' }
};
var hashMap = {
sha1: { hash: function (d) { return new _Sha1()._hash(d, 0, d.length); }, u: 20, v: 64 },
// sha256: { hash: (d: Uint8Array) => new _Sha256()._hash(d, 0, d.length), u: 32, v: 64 },
// sha384: { hash: (d: Uint8Array) => new _Sha384()._hash(d, 0, d.length), u: 48, v: 128 },
// sha512: { hash: (d: Uint8Array) => new _Sha512()._hash(d, 0, d.length), u: 64, v: 128 },
md5: { hash: function (d) { return new _MD5().hash(d, 0, d.length); }, u: 16, v: 64 }
// ripemd160: { hash: (d: Uint8Array) => new _RaceEvaluationMessageDigest()._hash(d, 0, d.length), u: 20, v: 64 }
};
if (!(oid in oidMap)) {
throw new Error("Unsupported oid: " + oid);
}
var algorithm = oidMap[oid];
var inputHash = hashMap[algorithm.hash]; //eslint-disable-line
var key = this._generateDerivedKey(passwordBytes, salt, 1, iterations, algorithm.keySize, inputHash);
var iv = algorithm.ivSize > 0
? this._generateDerivedKey(passwordBytes, salt, 2, iterations, algorithm.ivSize, inputHash)
: undefined;
var actualEncrypted = encryptedData;
var decrypted;
switch (algorithm.cipher) {
case 'AES':
decrypted = (new _AdvancedEncryption128Cipher(key))._decryptBlock(actualEncrypted, true, iv);
break;
case 'RC4':
decrypted = (new _NormalCipherFour(key))._decryptBlock(actualEncrypted);
break;
case 'DESEDE': {
var tripleDES = new _TripleDataEncryptionStandardCipher(key, false);
if (actualEncrypted.length % 8 !== 0) {
throw new Error('3DES expects multiples of 8 bytes');
}
var decryptedDESEDE = new Uint8Array(actualEncrypted.length);
var cbcBytes = iv.slice();
for (var i = 0; i < actualEncrypted.length; i += tripleDES._blockSize) {
var cipherBlock = actualEncrypted.slice(i, i + tripleDES._blockSize);
tripleDES._processBlock(actualEncrypted, i, decryptedDESEDE, i);
for (var j = 0; j < tripleDES._blockSize; j++) {
decryptedDESEDE[i + j] ^= cbcBytes[j];
}
cbcBytes = cipherBlock;
}
decrypted = decryptedDESEDE;
break;
}
case 'RC2': {
var rc2 = new _CipherTwo(key, algorithm.keySize * 8);
decrypted = rc2._decrypt(actualEncrypted, iv);
break;
}
case 'DES': {
if (actualEncrypted.length % 8 !== 0) {
throw new Error('DES expects multiples of 8 bytes');
}
var des = new _DataEncryptionStandardCipher(key, false);
var decryptedDes = new Uint8Array(actualEncrypted.length);
for (var i = 0; i < actualEncrypted.length; i += 8) {
des._processBlock(actualEncrypted, i, decryptedDes, i);
}
decrypted = decryptedDes;
break;
}
}
return decrypted;
};
/* eslint-disable */
/**
* Generate a derived key using PBKDF/PBE style iteration per PKCS specs.
*
* @private
* @param {Uint8Array} password - Password bytes.
* @param {Uint8Array} salt - Salt bytes.
* @param {number} id - Diversifier id.
* @param {number} iterations - Iteration count.
* @param {number} n - Desired key length in bytes.
* @param {{ hash(data: Uint8Array): Uint8Array; u: number; v: number }} hashValues - Hash function metadata.
* @returns {Uint8Array} Derived key of length `n`.
*/
_PdfPublicKeyCryptographyCertificate.prototype._generateDerivedKey = function (password, salt, id, iterations, n, hashValues) {
var u = hashValues.u, v = hashValues.v;
var D = new Uint8Array(v).fill(id);
var Slen = salt.length ? v * Math.ceil(salt.length / v) : 0;
var S = new Uint8Array(Slen);
for (var i = 0; i < Slen; ++i) {
S[i] = salt[i % salt.length];
}
var Plen = password.length ? v * Math.ceil(password.length / v) : 0;
var P = new Uint8Array(Plen);
for (var i = 0; i < Plen; ++i) {
P[i] = password[i % password.length];
}
var I = new Uint8Array(Slen + Plen);
I.set(S, 0);
I.set(P, Slen);
var c = Math.ceil(n / u);
var result = new Uint8Array(n);
var offset = 0;
for (var i = 0; i < c; ++i) {
var buf = new Uint8Array(D.length + I.length);
buf.set(D);
buf.set(I, D.length);
var Ai = hashValues.hash(buf);
for (var j = 1; j < iterations; ++j) {
Ai = hashValues.hash(Ai);
}
var blockLen = Math.min(u, n - offset);
result.set(Ai.subarray(0, blockLen), offset);
offset += blockLen;
var B = new Uint8Array(v);
for (var j = 0; j < v; ++j) {
B[j] = Ai[j % Ai.length];
}
for (var j = 0; j < I.length / v; ++j) {
this._adjust(I, j * v, B);
}
}
return result;
};
/* eslint-enable */
/**
* Internal helper used by the key derivation routine to add blocks.
*
* @private
* @param {Uint8Array} I - Buffer being adjusted.
* @param {number} offset - Offset within I to apply the adjustment.
* @param {Uint8Array} B - Block to add.
* @returns {void}
*/
_PdfPublicKeyCryptographyCertificate.prototype._adjust = function (I, offset, B) {
var x = B[B.length - 1] + I[offset + B.length - 1] + 1;
I[offset + B.length - 1] = x & 0xff;
x >>>= 8;
for (var i = B.length - 2; i >= 0; --i) {
x += B[i] + I[offset + i];
I[offset + i] = x & 0xff;
x >>>= 8;
}
};
/**
* Retrieve certificates associated with the provided key or friendly name.
*
* @private
* @param {string} certificateKey - Friendly name or identifier to lookup.
* @returns {_PdfX509Certificates} Matching certificates container or undefined.
*/
_PdfPublicKeyCryptographyCertificate.prototype._getCertificate = function (certificateKey) {
var certificates = this._certificates._get(certificateKey);
if (certificates && certificates instanceof _PdfX509Certificates) {
return certificates;
}
else {
var id = void 0;
if (this._localIdentifiers.has(certificateKey)) {
id = this._localIdentifiers.get(certificateKey);
}
if (typeof id !== 'undefined' && id !== null) {
var certificates_1 = this._keyCertificates.get(id);
if (certificates_1 && certificates_1 instanceof _PdfX509Certificates) {
return certificates_1;
}
}
else {
var key = certificateKey.toUpperCase().trim();
var certificates_2 = this._keyCertificates.get(key);
if (certificates_2 && certificates_2 instanceof _PdfX509Certificates) {
return certificates_2;
}
}
}
return undefined;
};
/**
* Parse raw RSA private key octets into component byte arrays.
*
* @private
* @param {Uint8Array} privateKeyOctets - DER-encoded RSA private key octets.
* @returns {Record<string,Uint8Array>} Map of RSA component names to bytes.
*/
_PdfPublicKeyCryptographyCertificate.prototype._parsePrivateKey = function (privateKeyOctets) {
var innerIsBER = _isBasicEncodingElement(privateKeyOctets);
var rsaElement = innerIsBER ? new _PdfBasicEncodingElement() : new _PdfUniqueEncodingElement();
rsaElement._fromBytes(privateKeyOctets);
var rsaSeq = rsaElement._getSequence();
return {
version: new Uint8Array([rsaSeq[0]._getInteger()]),
modulus: rsaSeq[1]._getValue(),
publicExponent: rsaSeq[2]._getValue(),
privateExponent: rsaSeq[3]._getValue(),
prime1: rsaSeq[4]._getValue(),
prime2: rsaSeq[5]._getValue(),
exponent1: rsaSeq[6]._getValue(),
exponent2: rsaSeq[7]._getValue(),
coefficient: rsaSeq[8]._getValue()
};
};
/**
* Build the certificate chain for a given certificate key/name.
*
* @private
* @param {string} key - Certificate key or friendly name.
* @returns {_PdfX509Certificates[]|null} Array of certificate containers or null.
*/
_PdfPublicKeyCryptographyCertificate.prototype._getCertificateChain = function (key) {
if (!this._keys.has(key)) {
return null;
}
var certificates = this._getCertificate(key);
if (!certificates) {
return null;
}
var certificateList = [];
var isContinue = true;
var _loop_1 = function () {
var x509Certificate = certificates._certificate;
var nextCertificate;
var x509Extension = x509Certificate._getExtension(new _PdfObjectIdentifier()._fromString('2.5.29.35'));
if (x509Extension) {
var extensionOctets = x509Extension._getValue();
var der = new _PdfUniqueEncodingElement();
der._fromBytes(extensionOctets);
var components = der._getSequence();
var keyIdentifierElement = components.find(function (el) { return el._tagClass === _TagClassType.context && el._getTagNumber() === 0; });
if (keyIdentifierElement) {
var keyID = keyIdentifierElement._getOctetString();
if (keyID) {
var certId_1 = new _PdfCertificateIdentifier({ id: keyID });
this_1._chainCertificates.forEach(function (value, key) {
if (_areUint8ArraysEqual(key._identifier, certId_1._identifier)) {
nextCertificate = value;
}
});
}
}
}
if (isContinue) {
certificateList.push(certificates);
certificates = nextCertificate && nextCertificate !== certificates ? nextCertificate : undefined;
}
};
var this_1 = this;
while (certificates && isContinue) {
_loop_1();
}
return certificateList.length > 0 ? certificateList : null;
};
return _PdfPublicKeyCryptographyCertificate;
}());
export { _PdfPublicKeyCryptographyCertificate };