Support CA fingerprint validation (#1499)
Co-authored-by: Aleh Zasypkin <aleh.zasypkin@gmail.com> Co-authored-by: Ioannis Kakavas <ioannis@elastic.co>
This commit is contained in:
committed by
delvedor
parent
563b7746cd
commit
a48ebc9442
@ -42,6 +42,7 @@ class Connection {
|
||||
this.headers = prepareHeaders(opts.headers, opts.auth)
|
||||
this.deadCount = 0
|
||||
this.resurrectTimeout = 0
|
||||
this.caFingerprint = opts.caFingerprint
|
||||
|
||||
this._openRequests = 0
|
||||
this._status = opts.status || Connection.statuses.ALIVE
|
||||
@ -123,10 +124,36 @@ class Connection {
|
||||
callback(new RequestAbortedError(), null)
|
||||
}
|
||||
|
||||
const onSocket = socket => {
|
||||
/* istanbul ignore else */
|
||||
if (!socket.isSessionReused()) {
|
||||
socket.once('secureConnect', () => {
|
||||
const issuerCertificate = getIssuerCertificate(socket)
|
||||
/* istanbul ignore next */
|
||||
if (issuerCertificate == null) {
|
||||
onError(new Error('Invalid or malformed certificate'))
|
||||
request.once('error', () => {}) // we need to catch the request aborted error
|
||||
return request.abort()
|
||||
}
|
||||
|
||||
// Check if fingerprint matches
|
||||
/* istanbul ignore else */
|
||||
if (this.caFingerprint !== issuerCertificate.fingerprint256) {
|
||||
onError(new Error('Server certificate CA fingerprint does not match the value configured in caFingerprint'))
|
||||
request.once('error', () => {}) // we need to catch the request aborted error
|
||||
return request.abort()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
request.on('response', onResponse)
|
||||
request.on('timeout', onTimeout)
|
||||
request.on('error', onError)
|
||||
request.on('abort', onAbort)
|
||||
if (this.caFingerprint != null) {
|
||||
request.on('socket', onSocket)
|
||||
}
|
||||
|
||||
// Disables the Nagle algorithm
|
||||
request.setNoDelay(true)
|
||||
@ -152,6 +179,7 @@ class Connection {
|
||||
request.removeListener('timeout', onTimeout)
|
||||
request.removeListener('error', onError)
|
||||
request.removeListener('abort', onAbort)
|
||||
request.removeListener('socket', onSocket)
|
||||
cleanedListeners = true
|
||||
}
|
||||
}
|
||||
@ -340,5 +368,25 @@ function prepareHeaders (headers = {}, auth) {
|
||||
return headers
|
||||
}
|
||||
|
||||
function getIssuerCertificate (socket) {
|
||||
let certificate = socket.getPeerCertificate(true)
|
||||
while (certificate && Object.keys(certificate).length > 0) {
|
||||
// invalid certificate
|
||||
if (certificate.issuerCertificate == null) {
|
||||
return null
|
||||
}
|
||||
|
||||
// We have reached the root certificate.
|
||||
// In case of self-signed certificates, `issuerCertificate` may be a circular reference.
|
||||
if (certificate.fingerprint256 === certificate.issuerCertificate.fingerprint256) {
|
||||
break
|
||||
}
|
||||
|
||||
// continue the loop
|
||||
certificate = certificate.issuerCertificate
|
||||
}
|
||||
return certificate
|
||||
}
|
||||
|
||||
module.exports = Connection
|
||||
module.exports.internals = { prepareHeaders }
|
||||
module.exports.internals = { prepareHeaders, getIssuerCertificate }
|
||||
|
||||
Reference in New Issue
Block a user