openhim-core
Version:
The OpenHIM core application that provides logging and routing of http requests
218 lines (177 loc) • 7.84 kB
text/coffeescript
Keystore = require('../model/keystore').Keystore
Q = require 'q'
logger = require 'winston'
authorisation = require './authorisation'
pem = require 'pem'
utils = require "../utils"
config = require "../config/config"
config.certificateManagement = config.get('certificateManagement')
exports.getServerCert = ->
# Must be admin
if authorisation.inGroup('admin', this.authenticated) is false
utils.logAndSetResponse this, 403, "User #{this.authenticated.email} is not an admin, API access to getServerCert denied.", 'info'
return
try
keystoreDoc = yield Keystore.findOne().lean('cert').exec()
keystoreDoc.cert.watchFSForCert = config.certificateManagement.watchFSForCert
this.body = keystoreDoc.cert
catch err
utils.logAndSetResponse this, 500, "Could not fetch the server cert via the API: #{err}", 'error'
exports.getCACerts = ->
# Must be admin
if authorisation.inGroup('admin', this.authenticated) is false
utils.logAndSetResponse this, 403, "User #{this.authenticated.email} is not an admin, API access to getCACerts denied.", 'info'
return
try
keystoreDoc = yield Keystore.findOne().select('ca').exec()
this.body = keystoreDoc.ca
catch err
utils.logAndSetResponse this, 500, "Could not fetch the ca certs trusted by this server via the API: #{err}", 'error'
exports.getCACert = (certId) ->
# Must be admin
if authorisation.inGroup('admin', this.authenticated) is false
utils.logAndSetResponse this, 403, "User #{this.authenticated.email} is not an admin, API access to getCACert by id denied.", 'info'
return
try
keystoreDoc = yield Keystore.findOne().select('ca').exec()
cert = keystoreDoc.ca.id(certId)
this.body = cert
catch err
utils.logAndSetResponse this, 500, "Could not fetch ca cert by id via the API: #{err}", 'error'
exports.setServerPassphrase = ->
# Must be admin
if authorisation.inGroup('admin', this.authenticated) is false
utils.logAndSetResponse this, 403, "User #{this.authenticated.email} is not an admin, API access to setServerPassphrase denied.", 'info'
return
try
passphrase = this.request.body.passphrase
keystoreDoc = yield Keystore.findOne().exec()
keystoreDoc.passphrase = passphrase
yield Q.ninvoke keystoreDoc, 'save'
this.status = 201
catch err
utils.logAndSetResponse this, 500, "Could not set the passphrase via the API: #{err}", 'error'
exports.setServerCert = ->
# Must be admin
if authorisation.inGroup('admin', this.authenticated) is false
utils.logAndSetResponse this, 403, "User #{this.authenticated.email} is not an admin, API access to setServerCert by id denied.", 'info'
return
if config.certificateManagement.watchFSForCert
utils.logAndSetResponse this, 400, "Failed to upload server certificate: Uploading of certificate while watchFSForCert is true is not allowed.", "info"
return
try
cert = this.request.body.cert
passphrase = this.request.body.passphrase
readCertificateInfo = Q.denodeify pem.readCertificateInfo
getFingerprint = Q.denodeify pem.getFingerprint
try
certInfo = yield readCertificateInfo cert
fingerprint = yield getFingerprint cert
catch err
return utils.logAndSetResponse this, 400, "Could not add server cert via the API: #{err}", 'error'
certInfo.data = cert
certInfo.fingerprint = fingerprint.fingerprint
keystoreDoc = yield Keystore.findOne().exec()
keystoreDoc.cert = certInfo
keystoreDoc.passphrase = passphrase
yield Q.ninvoke keystoreDoc, 'save'
this.status = 201
catch err
utils.logAndSetResponse this, 500, "Could not add server cert via the API: #{err}", 'error'
exports.setServerKey = ->
# Must be admin
if authorisation.inGroup('admin', this.authenticated) is false
utils.logAndSetResponse this, 403, "User #{this.authenticated.email} is not an admin, API access to getServerKey by id denied.", 'info'
return
try
key = this.request.body.key
passphrase = this.request.body.passphrase
keystoreDoc = yield Keystore.findOne().exec()
keystoreDoc.key = key
keystoreDoc.passphrase = passphrase
yield Q.ninvoke keystoreDoc, 'save'
this.status = 201
catch err
utils.logAndSetResponse this, 500, "Could not add server key via the API: #{err}", 'error'
exports.addTrustedCert = ->
# Must be admin
if authorisation.inGroup('admin', this.authenticated) is false
utils.logAndSetResponse this, 403, "User #{this.authenticated.email} is not an admin, API access to addTrustedCert by id denied.", 'info'
return
try
invalidCert = false
chain = this.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/)
certs = []
chain = chain.split "\n"
cert = []
for line in chain when line.length isnt 0
cert.push line
if line.match /-END CERTIFICATE-/
certs.push ((cert.join "\n") + "\n")
cert = []
keystoreDoc = yield Keystore.findOne().exec()
readCertificateInfo = Q.denodeify pem.readCertificateInfo
getFingerprint = Q.denodeify pem.getFingerprint
if certs.length < 1
invalidCert = true
for cert in certs
try
certInfo = yield readCertificateInfo cert
fingerprint = yield getFingerprint cert
catch err
invalidCert = true
continue
certInfo.data = cert
certInfo.fingerprint = fingerprint.fingerprint
keystoreDoc.ca.push certInfo
yield Q.ninvoke keystoreDoc, 'save'
if invalidCert
utils.logAndSetResponse this, 400, "Failed to add one more cert, are they valid? #{err}", 'error'
else
this.status = 201
catch err
utils.logAndSetResponse this, 500, "Could not add trusted cert via the API: #{err}", 'error'
exports.removeCACert = (certId) ->
# Must be admin
if authorisation.inGroup('admin', this.authenticated) is false
utils.logAndSetResponse this, 403, "User #{this.authenticated.email} is not an admin, API access to removeCACert by id denied.", 'info'
return
try
keystoreDoc = yield Keystore.findOne().exec()
keystoreDoc.ca.id(certId).remove()
yield Q.ninvoke keystoreDoc, 'save'
this.status = 200
catch err
utils.logAndSetResponse this, 500, "Could not remove ca cert by id via the API: #{err}", 'error'
exports.verifyServerKeys = ->
# Must be admin
if authorisation.inGroup('admin', this.authenticated) is false
utils.logAndSetResponse this, 403, "User #{this.authenticated.email} is not an admin, API access to verifyServerKeys.", 'info'
return
try
try
result = yield Q.nfcall getCertKeyStatus
catch err
return utils.logAndSetResponse this, 400, "Could not verify certificate and key, are they valid? #{err}", 'error'
this.body =
valid: result
this.status = 200
catch err
utils.logAndSetResponse this, 500, "Could not determine validity via the API: #{err}", 'error'
exports.getCertKeyStatus = getCertKeyStatus = (callback) ->
Keystore.findOne (err, keystoreDoc) ->
return callback err, null if err
# if the key is encrypted but no passphrase is supplied, return false instantly
if /Proc-Type:.*ENCRYPTED/.test(keystoreDoc.key) and (not keystoreDoc.passphrase? or keystoreDoc.passphrase.length == 0)
return callback null, false
pem.getModulusFromProtected keystoreDoc.key, keystoreDoc.passphrase, (err, keyModulus) ->
return callback err, null if err
pem.getModulus keystoreDoc.cert.data, (err, certModulus) ->
return callback err, null if err
# if cert/key match and are valid
if keyModulus.modulus is certModulus.modulus
return callback null, true
else
return callback null, false