@sphereon/ssi-sdk-ext.x509-utils
Version:
Sphereon SSI-SDK plugin functions for X.509 Certificate handling.
215 lines • 8.52 kB
JavaScript
;
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