Skip to content

Commit

Permalink
Refactor webserver keyring loading into handlers that can do either k…
Browse files Browse the repository at this point in the history
…eyring_js or zcrypto

Signed-off-by: 1000TurquoisePogs <[email protected]>
  • Loading branch information
1000TurquoisePogs committed Mar 4, 2024
1 parent f9de7cc commit 1a2f319
Show file tree
Hide file tree
Showing 5 changed files with 265 additions and 197 deletions.
1 change: 1 addition & 0 deletions lib/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ javaTypes.js
tomcatManager.js
apimlStorage.js
pluginStorage.js
keyring.js

# This program and the accompanying materials are
# made available under the terms of the Eclipse Public License v2.0 which accompanies
Expand Down
80 changes: 80 additions & 0 deletions lib/keyring.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
const os = require('os');
let keyring_js;
let zcrypto;

interface KeyringInterface {
getKey(user: string, ringName: string, label: string): any|undefined;
getCA(user: string, ringName: string, label: string): any|undefined;
getLabels(user: string, ringName: string, includeKeys: boolean): any|undefined;
}

export class KeyringJSKeyringHandler implements KeyringInterface {
constructor(){
if (os.platform() == 'os390') {
if (!keyring_js) {
keyring_js = require('keyring_js');
}
}
}

getKey(user: string, ringName: string, label: string): any|undefined {
return keyring_js.getPemEncodedData(user, ringName, label);
}

getCA(user: string, ringName: string, label: string): any|undefined {
return keyring_js.getPemEncodedData(user, ringName, label);
}

getLabels(user: string, ringName: string, includeKeys: boolean=false): any|undefined {
return keyring_js.listKeyring(user, ringName);
}
}

export class ZCryptoKeyringHandler implements KeyringInterface {
private ringHandles: any = {};

constructor(){
if (os.platform() == 'os390') {
if (!zcrypto) {
zcrypto = require('@1000turquoisepogs/zcrypto');
}
}
}

private getOrCreateRingHandle(user: string, ringName: string): any {
if (!this.ringHandles[user+'/'+ringName]) {
let crypt = new zcrypto.ZCrypto();
crypt.openKeyRing(user+'/'+ringName);
this.ringHandles[user+'/'+ringName] = crypt;
}
return this.ringHandles[user+'/'+ringName];
}

getKey(user: string, ringName: string, label: string): any|undefined {
let handle = this.getOrCreateRingHandle(user, ringName);
if (handle) {
let result = zcrypto.exportKeysToPKCS8(handle, label);
if (result) {
return { key: result.key, certificate: result.cert };
}
}
return undefined;
}

getCA(user: string, ringName: string, label: string): any|undefined {
let handle = this.getOrCreateRingHandle(user, ringName);
if (handle) {
return {certificate: zcrypto.exportCertToPEM(handle, label)};
}
return undefined;
}

getLabels(user: string, ringName: string, includeKeys: boolean=false): any|undefined {
let handle = this.getOrCreateRingHandle(user, ringName);
if (handle) {
let result = handle.getRecordLabels(includeKeys);
return result.map((name)=> { return {usage: 'CERTAUTH', label: name}});
}
return undefined;
}
}
64 changes: 32 additions & 32 deletions lib/webserver.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const util = require('./util');
const constants = require('./unp-constants');
const reader = require('./reader');
const crypto = require('crypto');
const { KeyringJSKeyringHandler, ZCryptoKeyringHandler } = require('./keyring');

const bootstrapLogger = util.loggers.bootstrapLogger;
const contentLogger = util.loggers.contentLogger;
Expand All @@ -32,20 +33,18 @@ const networkLogger = util.loggers.network;
const USE_KEYRING_JS = false;

const os = require('os');
let keyring_js;
let zcrypto;
let KeyringHandler;
try {
if (os.platform() == 'os390') {
if (USE_KEYRING_JS) {
keyring_js = require('keyring_js');
KeyringHandler = new KeyringJSKeyringHandler();
} else {
zcrypto = require('@1000turquoisepogs/zcrypto');
KeyringHandler = new ZCryptoKeyringHandler();
}
}
} catch (e) {
bootstrapLogger.warn('Could not load zcrypto library, SAF keyrings will be unavailable');
}

const CRYPTO_CONTENT_CERT=0;
const CRYPTO_CONTENT_KEY=1;
const CRYPTO_CONTENT_CA=2;
Expand Down Expand Up @@ -110,7 +109,7 @@ function getAttributeNameForCryptoType(locationType, cryptoType) {
default:
//TODO what happens with CRL?
if (cryptoType == CRYPTO_CONTENT_CERT || cryptoType == CRYPTO_CONTENT_CA) {
return zcrypto ? 'cert' : 'certificate';
return 'certificate';
} else if (cryptoType == CRYPTO_CONTENT_KEY) {
return 'key';
} else {
Expand Down Expand Up @@ -149,7 +148,7 @@ function loadPem(locations, type, keyrings, pass) {
if (saf && os.platform() != 'os390') {
bootstrapLogger.severe('ZWED0145E');//Cannot load SAF keyring content outside of z/OS'
process.exit(constants.EXIT_NO_SAFKEYRING);
} else if (saf && (keyring_js || zcrypto)) {
} else if (saf && KeyringHandler) {
saf.forEach((safEntry)=> {
/*
In the latest code it's possible the entry could start with
Expand All @@ -160,30 +159,17 @@ function loadPem(locations, type, keyrings, pass) {
const {userId, keyringName, label} = parseSafKeyringAddress(safRingAddress);
if (userId && keyringName && label) {
const cachedKey = 'safkeyring://'+safRingAddress;
let keyringData = keyrings[cachedKey];
const attribute = getAttributeNameForCryptoType('safkeyring', type);
try {
if (!keyringData) {
bootstrapLogger.debug(`Cache not found for ${cachedKey}`);
let keyringData;
if (!USE_KEYRING_JS) {
let crypt = new zcrypto.ZCrypto();
crypt.openKeyRing(keyringName);
switch (type) {
case CRYPTO_CONTENT_CERT:
case CRYPTO_CONTENT_KEY:
keyringData = zcrypto.exportKeysToPKCS8(crypt, label);
keyrings[cachedKey] = keyringData;
break;
case CRYPTO_CONTENT_CA:
case CRYPTO_CONTENT_CRL:
keyringData = {cert: zcrypto.exportCertToPEM(crypt, label)};
}

} else {
keyringData = keyring_js.getPemEncodedData(userId, keyringName, label);
keyrings[cachedKey] = keyringData;
}
let keyringData;
switch (type) {
case CRYPTO_CONTENT_CERT:
case CRYPTO_CONTENT_KEY:
keyringData = KeyringHandler.getKey(userId, keyringName, label);
break;
case CRYPTO_CONTENT_CA:
case CRYPTO_CONTENT_CRL:
keyringData = KeyringHandler.getCA(userId, keyringName, label);
}
if (keyringData) {
if (keyringData[attribute]) {
Expand All @@ -206,7 +192,7 @@ function loadPem(locations, type, keyrings, pass) {
userId, keyringName, label);
}
});
} else if (saf && !(keyring_js || zcrypto)) {
} else if (saf && !KeyringHandler) {
//Cannot load SAF keyring due to missing keyring_js or zcrypto library');
bootstrapLogger.warn('ZWED0150E');
}
Expand Down Expand Up @@ -315,8 +301,18 @@ WebServer.prototype = {
networkLogger.info('ZWED0075I', uniqueIps); //networkLogger.info('HTTPS config valid, will listen on: ' + uniqueIps);
}
config.https.ipAddresses = uniqueIps;
if(keyring_js && config.https.certificateAuthorities) {
if(KeyringHandler && config.https.certificateAuthorities) {
let newEntries = [];
let certLabels = [];
//collect list of certs known to us, to exclude from lookup of CAs.
const certsByType = splitCryptoLocationsByType(config.https.certificates);
if (certsByType.safkeyring) {
certLabels = certsByType.safkeyring.map((keyringLocation)=> {
let result = parseSafKeyringAddress(keyringLocation.startsWith('//') ? keyringLocation.substring(2) : keyringLocation);
return result.label;
});
}

const locationsByType = splitCryptoLocationsByType(config.https.certificateAuthorities);
if (locationsByType.safkeyring) {
locationsByType.safkeyring.forEach((keyringLocation)=> {
Expand All @@ -325,7 +321,11 @@ WebServer.prototype = {
let certificateList;
if(userId && keyringName) {
try {
certificateList = keyring_js.listKeyring(userId, keyringName);
let includingPrivateKey = false;
let certificatesFound = KeyringHandler.getLabels(userId, keyringName, includingPrivateKey);
if (certificatesFound && certificatesFound.length > 0) {
certificateList = certificatesFound.filter(name => !certLabels.includes(name));
}
} catch(e) {
bootstrapLogger.warn('ZWED0179W', keyringName, userId, e);
}
Expand Down
Loading

0 comments on commit 1a2f319

Please sign in to comment.