1
0
Fork 0
forked from svrjs/svrjs
This repository has been archived on 2024-11-10. You can view files and clone it, but cannot push or open issues or pull requests.
svrjs/node_modules/ocsp/lib/ocsp/server.js
2023-07-29 20:33:28 +02:00

197 lines
4.6 KiB
JavaScript

'use strict';
var ocsp = require('../ocsp');
var http = require('http');
var util = require('util');
var crypto = require('crypto');
var async = require('async');
var rfc2560 = require('asn1.js-rfc2560');
var rfc5280 = require('asn1.js-rfc5280');
function Server(options) {
http.Server.call(this, this.handler);
this.options = util._extend({
nextUpdate: 24 * 3600 * 1e3
}, options);
this.key = this.options.key;
this.cert = rfc5280.Certificate.decode(
ocsp.utils.toDER(options.cert, 'CERTIFICATE'),
'der');
this.cert = this.cert.tbsCertificate;
var issuerName = rfc5280.Name.encode(this.cert.subject, 'der');
var issuerKey = this.cert.subjectPublicKeyInfo.subjectPublicKey.data;
this.certID = {};
Object.keys(ocsp.utils.digestRev).forEach(function(digest) {
this.certID[digest] = {
issuerNameHash: crypto.createHash(digest).update(issuerName).digest(),
issuerKeyHash: crypto.createHash(digest).update(issuerKey).digest()
};
}, this);
this.certs = {};
}
util.inherits(Server, http.Server);
module.exports = Server;
Server.create = function create(options) {
return new Server(options);
};
Server.prototype.addCert = function addCert(serial, status, info) {
this.certs[serial.toString(16)] = {
type: status,
value: info
};
};
Server.prototype.handler = function handler(req, res) {
if (req.method !== 'POST')
return res.writeHead(400);
if (req.headers['content-type'] !== 'application/ocsp-request')
return res.writeHead(400);
var chunks = [];
req.on('readable', function() {
var chunk = req.read();
if (chunk)
chunks.push(chunk);
});
function errRes(status) {
return rfc2560.OCSPResponse.encode({
responseStatus: status
}, 'der');
}
function done(out) {
res.writeHead(200, {
'Content-Type': 'application/ocsp-response',
'Content-Length': out.length
});
res.end(out);
}
var self = this;
req.on('end', function() {
var body = Buffer.concat(chunks);
var ocspReq;
try {
ocspReq = rfc2560.OCSPRequest.decode(body, 'der');
} catch (e) {
return done(errRes('malformed_request'));
}
self.getResponses(ocspReq, function(err, responses) {
// Assume not found
if (err) {
res.writeHead(404);
res.end();
return;
}
return done(responses);
});
});
};
Server.prototype.getResponses = function getResponses(req, cb) {
var self = this;
var reqList = req.tbsRequest.requestList;
// TODO(indutny): support signed requests
async.map(reqList, function(req, cb) {
self.getResponse(req, cb);
}, function(err, responses) {
if (err)
return cb(err);
// TODO(indutny): send extensions
var basic = {
tbsResponseData: {
version: 'v1',
responderID: {
type: 'byKey',
value: self.certID.sha1.issuerKeyHash
},
producedAt: new Date(),
responses: responses
},
signatureAlgorithm: {
algorithm: ocsp.utils.signRev.sha512WithRSAEncryption
},
signature: null
// TODO(indutny): send certs?
};
var sign = crypto.createSign('sha512WithRSAEncryption');
sign.update(rfc2560.ResponseData.encode(basic.tbsResponseData, 'der'));
basic.signature = {
unused: 0,
data: sign.sign(self.key)
};
var res = {
responseStatus: 'successful',
responseBytes: {
responseType: 'id-pkix-ocsp-basic',
response: rfc2560.BasicOCSPResponse.encode(basic, 'der')
}
};
cb(null, rfc2560.OCSPResponse.encode(res, 'der'));
});
};
Server.prototype.getResponse = function getResponse(req, cb) {
var certID = req.reqCert;
var digestId = certID.hashAlgorithm.algorithm.join('.');
var digest = ocsp.utils.digest[digestId];
if (!digest)
return cb(new Error('Unknown digest: ' + digestId));
var expectedID = this.certID[digest];
if (!expectedID)
return cb(new Error('No pre-generated CertID for digest: ' + digest));
if (expectedID.issuerNameHash.toString('hex') !==
certID.issuerNameHash.toString('hex')) {
return cb(new Error('Issuer name mismatch'));
}
if (expectedID.issuerKeyHash.toString('hex') !==
certID.issuerKeyHash.toString('hex')) {
return cb(new Error('Issuer key mismatch'));
}
var serial = certID.serialNumber.toString(16);
var cert = this.certs[serial];
var response = {
certId: certID,
certStatus: null,
thisUpdate: new Date(),
nextUpdate: new Date(+new Date() + this.options.nextUpdate)
};
if (cert) {
response.certStatus = cert;
} else {
response.certStatus = {
type: 'unknown',
value: null
};
}
cb(null, response);
};