-
-
Save shigeki/986c53242f5bd3d78609 to your computer and use it in GitHub Desktop.
HTTPS Server to get A+ from SSL Labs Server Test
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require('tls').CLIENT_RENEG_LIMIT = 0; // disable renegatiation from client | |
var https = require('https'); | |
var http = require('http'); | |
var fs = require('fs'); | |
var ip = 'XXX.XXX.XXX.XXX'; | |
var port = 443; | |
var rfc2560 = require('asn1.js-rfc2560'); | |
var OCSPResponse = rfc2560.OCSPResponse; | |
var BasicOCSPResponse = rfc2560.BasicOCSPResponse; | |
var ocsp_uri = 'http://ocsp2.globalsign.com/gsorganizationvalsha2g2'; | |
var ocsp_dst = require('url').parse(ocsp_uri); | |
// ocsp_request.der can be generated beforehand by using openssl | |
// openssl ocsp -issuer /home/ohtsu/tmp/cert/ca.pem -cert /home/ohtsu/tmp/cert/server.pem -reqout req.der | |
var ocsp_request_der = fs.readFileSync('./ocsp_request.der'); | |
var ocsp_req_timeout = 3 * 1000; | |
var ocsp_cache = {nextUpdate: 0, der: null, lock: false}; | |
var opts = { | |
// See Cipher List in https://community.qualys.com/blogs/securitylabs/2013/08/05/configuring-apache-nginx-and-openssl-for-forward-secrecy | |
ciphers: 'EECDH+ECDSA+AESGCM:EECDH+aRSA+AESGCM:EECDH+ECDSA+SHA384:EECDH+ECDSA+SHA256:EECDH+aRSA+SHA384:EECDH+aRSA+SHA256:EECDH+aRSA+RC4:EECDH:EDH+aRSA:RC4:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS', | |
honorCipherOrder: true, | |
secureOptions: require('constants').SSL_OP_NO_SSLv3, // against POODLE attack | |
key: fs.readFileSync('/home/ohtsu/tmp/cert/server.key'), | |
cert: fs.readFileSync('/home/ohtsu/tmp/cert/server.cert'), | |
ca: fs.readFileSync('/home/ohtsu/tmp/cert/server.ca'), | |
dhparam: fs.readFileSync('./dhparam.pem') // generated by openssl dhparam 2048 -out dhparam.pem | |
}; | |
var hello = '<html><head></head><body>Hello TLS</body></html>'; | |
var session_cache = {}; | |
var session_id_list = []; | |
var session_cache_max = 100; | |
var server = https.createServer(opts, function(req, res) { | |
res.writeHead(200, {'content-type': 'text/html', | |
'strict-transport-security': 'max-age=15552000; includeSubDomains', | |
'content-length': Buffer.byteLength(hello)}); | |
res.end(hello); | |
}); | |
server.on('newSession', function(sessionId, sessionData, cb) { | |
if (session_id_list.length > session_cache_max) { | |
delete session_cache[session_id_list.shift()]; | |
} | |
session_id_list.push(sessionId); | |
session_cache[sessionId] = sessionData; | |
cb(null, sessionData); | |
}); | |
server.on('resumeSession', function(sessionId, cb) { | |
cb(null, session_cache[sessionId]); | |
}); | |
server.on('OCSPRequest', function(cert, issuer, cb) { | |
var now = Date.now(); | |
if (now > ocsp_cache.nextUpdate && !ocsp_cache.lock) { | |
ocsp_cache.lock = true; | |
ocsp_cache.der = null; | |
HandleOCSPrequest(cb); | |
} else { | |
cb(null, ocsp_cache.der); | |
} | |
}); | |
server.listen(port, ip, function() { | |
}); | |
function HandleOCSPrequest(cb) { | |
var opts = { | |
host: ocsp_dst.host, | |
method: 'POST', | |
path: ocsp_dst.path, | |
headers: {'content-type': 'application/ocsp-request', | |
'content-length': ocsp_request_der.length} | |
}; | |
var req = http.request(opts, function(res) { | |
var buflist = []; | |
res.on('data', function(chunk) { | |
buflist.push(chunk); | |
}); | |
res.on('end', function() { | |
var der = Buffer.concat(buflist); | |
var ocsp_res = OCSPResponse.decode(der, 'der'); | |
var b_res = BasicOCSPResponse.decode(ocsp_res.responseBytes.response, 'der'); | |
var res = b_res.tbsResponseData.responses[0]; | |
ocsp_cache = {nextUpdate: res.nextUpdate, der: der, lock: false}; | |
cb(null, der); | |
}); | |
}); | |
// Error and Timeout to OCSP server terminate OCSP stapling | |
req.setTimeout(ocsp_req_timeout, function() { | |
req.abort(); | |
req.emit('error', new Error('timeout')); | |
}); | |
req.on('error', function(e) { | |
if (ocsp_cache.lock === null) { | |
ocsp_cache = {nextUpdate: Infinity, der: null, lock: null}; | |
cb(null, null); | |
} | |
}); | |
req.end(ocsp_request_der); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment