UNPKG

openhim-core

Version:

The OpenHIM core application that provides logging and routing of http requests

263 lines (228 loc) 8.7 kB
import pem from 'pem' import { KeystoreModelAPI } from '../model/keystore' import * as authorisation from './authorisation' import * as utils from '../utils' import { config } from '../config' import { promisify } from 'util' config.certificateManagement = config.get('certificateManagement') export async function getServerCert (ctx) { // Must be admin if (authorisation.inGroup('admin', ctx.authenticated) === false) { utils.logAndSetResponse(ctx, 403, `User ${ctx.authenticated.email} is not an admin, API access to getServerCert denied.`, 'info') return } try { const keystoreDoc = await KeystoreModelAPI.findOne().lean('cert').exec() keystoreDoc.cert.watchFSForCert = config.certificateManagement.watchFSForCert ctx.body = keystoreDoc.cert } catch (err) { utils.logAndSetResponse(ctx, 500, `Could not fetch the server cert via the API: ${err}`, 'error') } } export async function getCACerts (ctx) { // Must be admin if (authorisation.inGroup('admin', ctx.authenticated) === false) { utils.logAndSetResponse(ctx, 403, `User ${ctx.authenticated.email} is not an admin, API access to getCACerts denied.`, 'info') return } try { const keystoreDoc = await KeystoreModelAPI.findOne().select('ca').exec() ctx.body = keystoreDoc.ca } catch (err) { utils.logAndSetResponse(ctx, 500, `Could not fetch the ca certs trusted by this server via the API: ${err}`, 'error') } } export async function getCACert (ctx, certId) { // Must be admin if (authorisation.inGroup('admin', ctx.authenticated) === false) { utils.logAndSetResponse(ctx, 403, `User ${ctx.authenticated.email} is not an admin, API access to getCACert by id denied.`, 'info') return } try { const keystoreDoc = await KeystoreModelAPI.findOne().select('ca').exec() const cert = keystoreDoc.ca.id(certId) ctx.body = cert } catch (err) { utils.logAndSetResponse(ctx, 500, `Could not fetch ca cert by id via the API: ${err}`, 'error') } } export async function setServerPassphrase (ctx) { // Must be admin if (authorisation.inGroup('admin', ctx.authenticated) === false) { utils.logAndSetResponse(ctx, 403, `User ${ctx.authenticated.email} is not an admin, API access to setServerPassphrase denied.`, 'info') return } try { const {passphrase} = ctx.request.body const keystoreDoc = await KeystoreModelAPI.findOne().exec() keystoreDoc.passphrase = passphrase await keystoreDoc.save() ctx.status = 201 } catch (err) { utils.logAndSetResponse(ctx, 500, `Could not set the passphrase via the API: ${err}`, 'error') } } export async function setServerCert (ctx) { // Must be admin let err if (authorisation.inGroup('admin', ctx.authenticated) === false) { utils.logAndSetResponse(ctx, 403, `User ${ctx.authenticated.email} is not an admin, API access to setServerCert by id denied.`, 'info') return } if (config.certificateManagement.watchFSForCert) { utils.logAndSetResponse(ctx, 400, 'Failed to upload server certificate: Uploading of certificate while watchFSForCert is true is not allowed.', 'info') return } try { let certInfo let fingerprint const {cert, passphrase} = ctx.request.body const readCertificateInfo = promisify(pem.readCertificateInfo) const getFingerprint = promisify(pem.getFingerprint) try { certInfo = await readCertificateInfo(cert) fingerprint = await getFingerprint(cert) } catch (error) { err = error return utils.logAndSetResponse(ctx, 400, `Could not add server cert via the API: ${err}`, 'error') } certInfo.data = cert certInfo.fingerprint = fingerprint.fingerprint const keystoreDoc = await KeystoreModelAPI.findOne().exec() keystoreDoc.cert = certInfo keystoreDoc.passphrase = passphrase await keystoreDoc.save() ctx.status = 201 } catch (error1) { err = error1 utils.logAndSetResponse(ctx, 500, `Could not add server cert via the API: ${err}`, 'error') } } export async function setServerKey (ctx) { // Must be admin if (authorisation.inGroup('admin', ctx.authenticated) === false) { utils.logAndSetResponse(ctx, 403, `User ${ctx.authenticated.email} is not an admin, API access to getServerKey by id denied.`, 'info') return } try { const {key, passphrase} = ctx.request.body const keystoreDoc = await KeystoreModelAPI.findOne().exec() keystoreDoc.key = key keystoreDoc.passphrase = passphrase await keystoreDoc.save() ctx.status = 201 } catch (err) { return utils.logAndSetResponse(ctx, 500, `Could not add server key via the API: ${err}`, 'error') } } export async function addTrustedCert (ctx) { // Must be admin let err if (authorisation.inGroup('admin', ctx.authenticated) === false) { utils.logAndSetResponse(ctx, 403, `User ${ctx.authenticated.email} is not an admin, API access to addTrustedCert by id denied.`, 'info') return } try { let invalidCert = false let chain = ctx.request.body.cert // Parse into an array in case this is a cert chain // (code derived from: http://www.benjiegillam.com/2012/06/node-dot-js-ssl-certificate-chain/) const certs = [] chain = chain.split('\n') let cert = [] for (const line of Array.from(chain)) { if (line.length !== 0) { cert.push(line) if (line.match(/-END CERTIFICATE-/)) { certs.push((`${cert.join('\n')}\n`)) cert = [] } } } const keystoreDoc = await KeystoreModelAPI.findOne().exec() const readCertificateInfo = promisify(pem.readCertificateInfo) const getFingerprint = promisify(pem.getFingerprint) if (certs.length < 1) { invalidCert = true } for (const cert of Array.from(certs)) { let certInfo let fingerprint try { certInfo = await readCertificateInfo(cert) fingerprint = await getFingerprint(cert) } catch (error) { err = error invalidCert = true continue } certInfo.data = cert certInfo.fingerprint = fingerprint.fingerprint keystoreDoc.ca.push(certInfo) } await keystoreDoc.save() if (invalidCert) { utils.logAndSetResponse(ctx, 400, `Failed to add one more cert, are they valid? ${err}`, 'error') } else { ctx.status = 201 } } catch (error1) { err = error1 utils.logAndSetResponse(ctx, 500, `Could not add trusted cert via the API: ${err}`, 'error') } } export async function removeCACert (ctx, certId) { // Must be admin if (authorisation.inGroup('admin', ctx.authenticated) === false) { utils.logAndSetResponse(ctx, 403, `User ${ctx.authenticated.email} is not an admin, API access to removeCACert by id denied.`, 'info') return } try { const keystoreDoc = await KeystoreModelAPI.findOne().exec() keystoreDoc.ca.id(certId).remove() await keystoreDoc.save() ctx.status = 200 } catch (err) { utils.logAndSetResponse(ctx, 500, `Could not remove ca cert by id via the API: ${err}`, 'error') } } export async function verifyServerKeys (ctx) { // Must be admin if (authorisation.inGroup('admin', ctx.authenticated) === false) { utils.logAndSetResponse(ctx, 403, `User ${ctx.authenticated.email} is not an admin, API access to verifyServerKeys.`, 'info') return } try { let result try { result = await promisify(getCertKeyStatus)() } catch (error) { return utils.logAndSetResponse(ctx, 400, `Could not verify certificate and key, are they valid? ${error}`, 'error') } ctx.body = {valid: result} ctx.status = 200 } catch (error) { utils.logAndSetResponse(ctx, 500, `Could not determine validity via the API: ${error}`, 'error') } } export function getCertKeyStatus (callback) { return KeystoreModelAPI.findOne((err, keystoreDoc) => { if (err) { return callback(err, null) } // if the key is encrypted but no passphrase is supplied, return false instantly if (/Proc-Type:.*ENCRYPTED/.test(keystoreDoc.key) && ((keystoreDoc.passphrase == null) || (keystoreDoc.passphrase.length === 0))) { return callback(null, false) } return pem.getModulus(keystoreDoc.key, keystoreDoc.passphrase, (err, keyModulus) => { if (err) { return callback(err, null) } return pem.getModulus(keystoreDoc.cert.data, (err, certModulus) => { if (err) { return callback(err, null) } // if cert/key match and are valid if (keyModulus.modulus === certModulus.modulus) { return callback(null, true) } else { return callback(null, false) } }) }) }) }