UNPKG

@sphereon/ssi-sdk-ext.x509-utils

Version:

Sphereon SSI-SDK plugin functions for X.509 Certificate handling.

215 lines 8.52 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; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.hexToPEM = exports.hexToBase64 = exports.base64ToHex = exports.PEMToHex = exports.publicKeyHexFromPEM = exports.hexKeyFromPEMBasedJwk = exports.privateKeyHexFromPEM = exports.PEMToJwk = exports.jwkToPEM = exports.toKeyObject = exports.areCertificatesEqual = exports.pemOrDerToX509Certificate = void 0; exports.pemCertChainTox5c = pemCertChainTox5c; exports.x5cToPemCertChain = x5cToPemCertChain; exports.PEMToBinary = PEMToBinary; exports.PEMToDer = PEMToDer; exports.derToPEM = derToPEM; const pkijs_1 = require("pkijs"); const u8a = __importStar(require("uint8arrays")); // @ts-ignore const keyto_1 = __importDefault(require("@trust/keyto")); // Based on (MIT licensed): // https://github.com/hildjj/node-posh/blob/master/lib/index.js function pemCertChainTox5c(cert, maxDepth) { if (!maxDepth) { maxDepth = 0; } /* * Convert a PEM-encoded certificate to the version used in the x5c element * of a [JSON Web Key](http://tools.ietf.org/html/draft-ietf-jose-json-web-key). * * `cert` PEM-encoded certificate chain * `maxdepth` The maximum number of certificates to use from the chain. */ const intermediate = cert .replace(/-----[^\n]+\n?/gm, ',') .replace(/\n/g, '') .replace(/\r/g, ''); let x5c = intermediate.split(',').filter(function (c) { return c.length > 0; }); if (maxDepth > 0) { x5c = x5c.splice(0, maxDepth); } return x5c; } function x5cToPemCertChain(x5c, maxDepth) { if (!maxDepth) { maxDepth = 0; } const length = maxDepth === 0 ? x5c.length : Math.min(maxDepth, x5c.length); let pem = ''; for (let i = 0; i < length; i++) { pem += derToPEM(x5c[i], 'CERTIFICATE'); } return pem; } const pemOrDerToX509Certificate = (cert) => { let DER = typeof cert === 'string' ? cert : undefined; if (typeof cert === 'object' && !(cert instanceof Uint8Array)) { // X509Certificate object return pkijs_1.Certificate.fromBER(cert.rawData); } else if (typeof cert !== 'string') { return pkijs_1.Certificate.fromBER(cert); } else if (cert.includes('CERTIFICATE')) { DER = PEMToDer(cert); } if (!DER) { throw Error('Invalid cert input value supplied. PEM, DER, Bytes and X509Certificate object are supported'); } return pkijs_1.Certificate.fromBER(u8a.fromString(DER, 'base64pad')); }; exports.pemOrDerToX509Certificate = pemOrDerToX509Certificate; const areCertificatesEqual = (cert1, cert2) => { return cert1.signatureValue.isEqual(cert2.signatureValue); }; exports.areCertificatesEqual = areCertificatesEqual; const toKeyObject = (PEM, visibility = 'public') => { const jwk = (0, exports.PEMToJwk)(PEM, visibility); const keyVisibility = jwk.d ? 'private' : 'public'; const keyHex = keyVisibility === 'private' ? (0, exports.privateKeyHexFromPEM)(PEM) : (0, exports.publicKeyHexFromPEM)(PEM); return { pem: (0, exports.hexToPEM)(keyHex, visibility), jwk, keyHex, keyType: keyVisibility, }; }; exports.toKeyObject = toKeyObject; const jwkToPEM = (jwk, visibility = 'public') => { return keyto_1.default.from(jwk, 'jwk').toString('pem', visibility === 'public' ? 'public_pkcs8' : 'private_pkcs8'); }; exports.jwkToPEM = jwkToPEM; const PEMToJwk = (pem, visibility = 'public') => { return keyto_1.default.from(pem, 'pem').toJwk(visibility); }; exports.PEMToJwk = PEMToJwk; const privateKeyHexFromPEM = (PEM) => { return (0, exports.PEMToHex)(PEM); }; exports.privateKeyHexFromPEM = privateKeyHexFromPEM; const hexKeyFromPEMBasedJwk = (jwk, visibility = 'public') => { if (visibility === 'private') { return (0, exports.privateKeyHexFromPEM)((0, exports.jwkToPEM)(jwk, 'private')); } else { return (0, exports.publicKeyHexFromPEM)((0, exports.jwkToPEM)(jwk, 'public')); } }; exports.hexKeyFromPEMBasedJwk = hexKeyFromPEMBasedJwk; const publicKeyHexFromPEM = (PEM) => { const hex = (0, exports.PEMToHex)(PEM); if (PEM.includes('CERTIFICATE')) { throw Error('Cannot directly deduce public Key from PEM Certificate yet'); } else if (!PEM.includes('PRIVATE')) { return hex; } const publicJwk = (0, exports.PEMToJwk)(PEM, 'public'); const publicPEM = (0, exports.jwkToPEM)(publicJwk, 'public'); return (0, exports.PEMToHex)(publicPEM); }; exports.publicKeyHexFromPEM = publicKeyHexFromPEM; const PEMToHex = (PEM, headerKey) => { if (PEM.indexOf('-----BEGIN ') == -1) { throw Error(`PEM header not found: ${headerKey}`); } let strippedPem; if (headerKey) { strippedPem = PEM.replace(new RegExp('^[^]*-----BEGIN ' + headerKey + '-----'), ''); strippedPem = strippedPem.replace(new RegExp('-----END ' + headerKey + '-----[^]*$'), ''); } else { strippedPem = PEM.replace(/^[^]*-----BEGIN [^-]+-----/, ''); strippedPem = strippedPem.replace(/-----END [^-]+-----[^]*$/, ''); } return (0, exports.base64ToHex)(strippedPem, 'base64pad'); }; exports.PEMToHex = PEMToHex; function PEMToBinary(pem) { const pemContents = pem .replace(/^[^]*-----BEGIN [^-]+-----/, '') .replace(/-----END [^-]+-----[^]*$/, '') .replace(/\s/g, ''); return u8a.fromString(pemContents, 'base64pad'); } /** * Converts a base64 encoded string to hex string, removing any non-base64 characters, including newlines * @param input The input in base64, with optional newlines * @param inputEncoding */ const base64ToHex = (input, inputEncoding) => { const base64NoNewlines = input.replace(/[^0-9A-Za-z_\-~\/+=]*/g, ''); return u8a.toString(u8a.fromString(base64NoNewlines, inputEncoding ? inputEncoding : 'base64pad'), 'base16'); }; exports.base64ToHex = base64ToHex; const hexToBase64 = (input, targetEncoding) => { let hex = typeof input === 'string' ? input : input.toString(16); if (hex.length % 2 === 1) { hex = `0${hex}`; } return u8a.toString(u8a.fromString(hex, 'base16'), targetEncoding ? targetEncoding : 'base64pad'); }; exports.hexToBase64 = hexToBase64; const hexToPEM = (hex, type) => { const base64 = (0, exports.hexToBase64)(hex, 'base64pad'); const headerKey = type === 'private' ? 'RSA PRIVATE KEY' : 'PUBLIC KEY'; if (type === 'private') { const pem = derToPEM(base64, headerKey); try { (0, exports.PEMToJwk)(pem); // We only use it to test the private key return pem; } catch (error) { return derToPEM(base64, 'PRIVATE KEY'); } } return derToPEM(base64, headerKey); }; exports.hexToPEM = hexToPEM; function PEMToDer(pem) { return pem.replace(/(-----(BEGIN|END) CERTIFICATE-----|[\n\r])/g, ''); } function derToPEM(cert, headerKey) { const key = headerKey !== null && headerKey !== void 0 ? headerKey : 'CERTIFICATE'; if (cert.includes(key)) { // Was already in PEM it seems return cert; } const matches = cert.match(/.{1,64}/g); if (!matches) { throw Error('Invalid cert input value supplied'); } return `-----BEGIN ${key}-----\n${matches.join('\n')}\n-----END ${key}-----\n`; } //# sourceMappingURL=x509-utils.js.map