UNPKG

ec-sri-invoice-signer

Version:
135 lines (134 loc) 6.91 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.extractX509Data = exports.extractIssuerData = exports.extractPrivateKeyData = exports.extractPrivateKeyAndCertificateFromPkcs12 = exports.getHash = exports.sign = void 0; const forge = __importStar(require("node-forge")); const errors_1 = require("./errors"); const sign = (data, privateKey) => { return forge.util.encode64(privateKey.sign(forge.sha1.create().update(data, 'utf8'))); }; exports.sign = sign; const getHash = (data) => { return forge.util.encode64(forge.sha1.create().update(data, 'utf8').digest().bytes()); }; exports.getHash = getHash; const getBancoCentralPkcs12PrivateKey = (pkcs8ShroudedKeyBags) => { const privateKeyBag = pkcs8ShroudedKeyBags.find((bag) => { var _a, _b; const name = (_b = (_a = bag === null || bag === void 0 ? void 0 : bag.attributes) === null || _a === void 0 ? void 0 : _a.friendlyName) === null || _b === void 0 ? void 0 : _b[0]; return /signing key/i.test(name); }); if (!privateKeyBag) { throw new errors_1.UnsuportedPkcs12Error("No key bag with friendly name 'Signing Key' found in the key bags of 'Banco Central del Ecuador' .p12"); } const privateKey = privateKeyBag.key; if (!privateKey) { throw new errors_1.UnsuportedPkcs12Error("No valid key found in 'Banco Central del Ecuador' .p12"); } return privateKey; }; const extractPrivateKeyAndCertificateFromPkcs12 = (pkcs12RawData, password = '') => { var _a, _b, _c, _d, _e; const pkcs12InBase64 = typeof pkcs12RawData === 'string' ? pkcs12RawData : pkcs12RawData.toString('base64'); const pkcs12InDer = forge.util.decode64(pkcs12InBase64); const p12Asn1 = forge.asn1.fromDer(pkcs12InDer); const p12 = forge.pkcs12.pkcs12FromAsn1(p12Asn1, password); const certBags = p12.getBags({ bagType: forge.pki.oids.certBag }); const certBag = (_a = certBags[forge.pki.oids.certBag]) === null || _a === void 0 ? void 0 : _a[0]; const pkcs8ShroudedKeyBags = p12.getBags({ bagType: forge.pki.oids.pkcs8ShroudedKeyBag }); if (!certBag || !pkcs8ShroudedKeyBags) { throw new errors_1.UnsuportedPkcs12Error(); } const friendlyName = (_c = (_b = certBag === null || certBag === void 0 ? void 0 : certBag.attributes) === null || _b === void 0 ? void 0 : _b.friendlyName) === null || _c === void 0 ? void 0 : _c[0]; const certificate = certBag.cert; if (!certificate) { throw new errors_1.UnsuportedPkcs12Error("Couldn't find its certificate"); } let privateKey = null; if (/banco central/i.test(friendlyName)) { privateKey = getBancoCentralPkcs12PrivateKey((_d = pkcs8ShroudedKeyBags[forge.pki.oids.pkcs8ShroudedKeyBag]) !== null && _d !== void 0 ? _d : []); } else { const firstPkcs8ShroudedKeyBag = (_e = pkcs8ShroudedKeyBags[forge.pki.oids.pkcs8ShroudedKeyBag]) === null || _e === void 0 ? void 0 : _e[0]; privateKey = (firstPkcs8ShroudedKeyBag === null || firstPkcs8ShroudedKeyBag === void 0 ? void 0 : firstPkcs8ShroudedKeyBag.key) ? firstPkcs8ShroudedKeyBag.key : null; } if (!privateKey) { throw new errors_1.UnsuportedPkcs12Error("Couldn't find its private key"); } return { privateKey, certificate }; }; exports.extractPrivateKeyAndCertificateFromPkcs12 = extractPrivateKeyAndCertificateFromPkcs12; const normalizeIssuerAttributeShortName = (shortName) => { switch (shortName) { case 'E': // As required by the SRI validator code in this line (https://github.com/gdiazs/MITyCLib/blob/master/MITyCLibXADES/src/main/java/es/mityc/firmaJava/libreria/xades/ValidarFirmaXML.java#L2139). // X500Principal needs EMAILADDRESS instead of E (https://docs.oracle.com/javase/7/docs/api/javax/security/auth/x500/X500Principal.html#X500Principal(java.lang.String)) and has been seen that some certificate issuers set the email address with 'E' shortName. // The oid for email (1.2.840.113549.1.9.1) could also be used, but that's a bit cryptic and we know the SRI accepts EMAILADDRESS without issue so no need to be that generic. return 'EMAILADDRESS'; default: return shortName; } ; }; const extractIssuerData = (certificate) => { const issuerName = certificate.issuer.attributes.reverse().filter((attr) => attr.shortName || attr.type).map((attr) => { if (attr.shortName) { const normalizedShortName = normalizeIssuerAttributeShortName(attr.shortName); return `${normalizedShortName}=${attr.value}`; } else { return `${attr.type}=${attr.value}`; } }).join(','); // .reverse to follow convention of country-name-is-last seen in the SRI example return issuerName; }; exports.extractIssuerData = extractIssuerData; const extractX509Data = (certificate) => { const serialNumber = new forge.jsbn.BigInteger(Array.from(Buffer.from(certificate.serialNumber, 'hex'))).toString(); const issuerName = extractIssuerData(certificate); const certificateAsAsn1 = forge.pki.certificateToAsn1(certificate); const contentAsDer = forge.asn1.toDer(certificateAsAsn1); const contentHash = forge.util.encode64(forge.sha1.create().update(contentAsDer.bytes()).digest().bytes()); const content = forge.util.encode64(contentAsDer.bytes()); return { content, contentHash, issuerName, serialNumber }; }; exports.extractX509Data = extractX509Data; const extractPrivateKeyData = (privateKey) => { const modulus = Buffer.from(privateKey.e.toString(), 'hex').toString('base64'); const exponent = Buffer.from(privateKey.n.toString(), 'hex').toString('base64'); return { modulus, exponent }; }; exports.extractPrivateKeyData = extractPrivateKeyData;