UNPKG

@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
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 };