UNPKG

@pedwise/next-firebase-auth-edge

Version:

Next.js 13 Firebase Authentication for Edge and server runtimes. Dedicated for Next 13 server components. Compatible with Next.js middleware.

182 lines 6.37 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.pemToPublicKey = void 0; const utils_1 = require("./jwt/utils"); function berToJavaScript(byteArray) { const result = {}; let position = 0; result.cls = getClass(); result.structured = getStructured(); result.tag = getTag(); let length = getLength(); // As encoded, which may be special value 0 if (length === 0x80) { length = 0; while (byteArray[position + length] !== 0 || byteArray[position + length + 1] !== 0) { length += 1; } result.byteLength = position + length + 2; result.contents = byteArray.subarray(position, position + length); } else { result.byteLength = position + length; result.contents = byteArray.subarray(position, result.byteLength); } result.raw = byteArray.subarray(0, result.byteLength); // May not be the whole input array return result; function getClass() { return (byteArray[position] & 0xc0) / 64; } function getStructured() { // Consumes no bytes return (byteArray[0] & 0x20) === 0x20; } function getTag() { let tag = byteArray[0] & 0x1f; position += 1; if (tag === 0x1f) { tag = 0; while (byteArray[position] >= 0x80) { tag = tag * 128 + byteArray[position] - 0x80; position += 1; } tag = tag * 128 + byteArray[position] - 0x80; position += 1; } return tag; } function getLength() { let length; if (byteArray[position] < 0x80) { length = byteArray[position]; position += 1; } else { const numberOfDigits = byteArray[position] & 0x7f; position += 1; length = 0; for (let i = 0; i < numberOfDigits; i++) { length = length * 256 + byteArray[position]; position += 1; } } return length; } } function berListToJavaScript(byteArray) { const result = []; let nextPosition = 0; while (nextPosition < byteArray.length) { const nextPiece = berToJavaScript(byteArray.subarray(nextPosition)); result.push(nextPiece); nextPosition += nextPiece.byteLength; } return result; } function parseTBSCertificate(asn1) { if (asn1.cls !== 0 || asn1.tag !== 16 || !asn1.structured) { throw new Error("This can't be a TBSCertificate. Wrong data type."); } const pieces = berListToJavaScript(asn1.contents); if (pieces.length < 7) { throw new Error("Bad TBS Certificate. There are fewer than the seven required children."); } return { asn1, version: pieces[0], serialNumber: pieces[1], signature: parseAlgorithmIdentifier(pieces[2]), issuer: pieces[3], validity: pieces[4], subject: pieces[5], subjectPublicKeyInfo: parseSubjectPublicKeyInfo(pieces[6]), }; } function parseAlgorithmIdentifier(asn1) { if (asn1.cls !== 0 || asn1.tag !== 16 || !asn1.structured) { throw new Error("Bad algorithm identifier. Not a SEQUENCE."); } const pieces = berListToJavaScript(asn1.contents); if (pieces.length > 2) { throw new Error("Bad algorithm identifier. Contains too many child objects."); } const encodedAlgorithm = pieces[0]; if (encodedAlgorithm.cls !== 0 || encodedAlgorithm.tag !== 6 || encodedAlgorithm.structured) { throw new Error("Bad algorithm identifier. Does not begin with an OBJECT IDENTIFIER."); } return { asn1, algorithm: berObjectIdentifierValue(encodedAlgorithm.contents), parameters: pieces.length === 2 ? { asn1: pieces[1] } : null, }; } function berObjectIdentifierValue(byteArray) { let oid = Math.floor(byteArray[0] / 40) + "." + (byteArray[0] % 40); let position = 1; while (position < byteArray.length) { let nextInteger = 0; while (byteArray[position] >= 0x80) { nextInteger = nextInteger * 0x80 + (byteArray[position] & 0x7f); position += 1; } nextInteger = nextInteger * 0x80 + byteArray[position]; position += 1; oid += "." + nextInteger; } return oid; } function parseSubjectPublicKeyInfo(asn1) { if (asn1.cls !== 0 || asn1.tag !== 16 || !asn1.structured) { throw new Error("Bad SPKI. Not a SEQUENCE."); } const pieces = berListToJavaScript(asn1.contents); if (pieces.length !== 2) { throw new Error("Bad SubjectPublicKeyInfo. Wrong number of child objects."); } return { asn1, algorithm: parseAlgorithmIdentifier(pieces[0]), bits: berBitStringValue(pieces[1].contents), }; } function berBitStringValue(byteArray) { return { unusedBits: byteArray[0], bytes: byteArray.subarray(1), }; } const parseSignatureAlgorithm = parseAlgorithmIdentifier; function parseSignatureValue(asn1) { if (asn1.cls !== 0 || asn1.tag !== 3 || asn1.structured) { throw new Error("Bad signature value. Not a BIT STRING."); } return { asn1, bits: berBitStringValue(asn1.contents), }; } function parseCertificate(byteArray) { const asn1 = berToJavaScript(byteArray); if (asn1.cls !== 0 || asn1.tag !== 16 || !asn1.structured) { throw new Error("This can't be an X.509 certificate. Wrong data type."); } const pieces = berListToJavaScript(asn1.contents); if (pieces.length !== 3) { throw new Error("Certificate contains more than the three specified children."); } return { asn1, tbsCertificate: parseTBSCertificate(pieces[0]), signatureAlgorithm: parseSignatureAlgorithm(pieces[1]), signatureValue: parseSignatureValue(pieces[2]), }; } function pemToPublicKey(pem) { const der = (0, utils_1.base64StringToByteArray)(pem); const certificate = parseCertificate(der); return crypto.subtle.importKey("spki", certificate.tbsCertificate.subjectPublicKeyInfo.asn1.raw, { name: "RSASSA-PKCS1-v1_5", hash: { name: "SHA-256" } }, true, ["verify"]); } exports.pemToPublicKey = pemToPublicKey; //# sourceMappingURL=pem-to-public-key.js.map