Fixed CA handling for SNI certificates

This commit is contained in:
Andris Reinman 2022-08-16 15:22:47 +03:00
parent d8150b7d2b
commit 3f738389ba
No known key found for this signature in database
GPG key ID: DC6C83F4D584D364
5 changed files with 35 additions and 22 deletions

10
api.js
View file

@ -145,10 +145,7 @@ if (config.api.secure && certOptions.key) {
let httpsServerOptions = {};
httpsServerOptions.key = certOptions.key;
if (certOptions.ca) {
httpsServerOptions.ca = certOptions.ca;
}
httpsServerOptions.cert = certOptions.cert;
httpsServerOptions.cert = tools.buildCertChain(certOptions.cert, certOptions.ca);
let defaultSecureContext = tls.createSecureContext(httpsServerOptions);
@ -534,10 +531,7 @@ module.exports = done => {
namespace: 'mail'
});
if (config.acme && config.acme.agent && config.acme.agent.enabled) {
acmeRoutes(db, server, { disableRedirect: true });
}
acmeRoutes(db, server, { disableRedirect: true });
usersRoutes(db, server, userHandler, settingsHandler);
addressesRoutes(db, server, userHandler, settingsHandler);
mailboxesRoutes(db, server, mailboxHandler);

View file

@ -54,7 +54,8 @@ const tlsDefaults = {
'-----END CERTIFICATE-----',
honorCipherOrder: true,
requestOCSP: false,
sessionIdContext: crypto.createHash('sha1').update(process.argv.join(' ')).digest('hex').slice(0, 32)
sessionIdContext: crypto.createHash('sha1').update(process.argv.join(' ')).digest('hex').slice(0, 32),
minVersion: 'TLSv1'
};
/**

View file

@ -295,8 +295,6 @@ class CertHandler {
certData.cert = cert;
}
certData.ca = [].concat(ca || []);
if (primaryCert) {
try {
const parsedCert = forge.pki.certificateFromPem(primaryCert);
@ -558,7 +556,11 @@ class CertHandler {
// key might be encrypted
let privateKey = await decrypt(certData.privateKey, this.secret, this.cipher);
let serviceCtxOpts = { key: privateKey, cert: certData.cert, ca: certData.ca };
let serviceCtxOpts = {
key: privateKey,
cert: tools.buildCertChain(certData.cert, certData.ca)
};
for (let key of ['dhparam']) {
if (serverOptions[key]) {
serviceCtxOpts[key] = serverOptions[key];

View file

@ -4,6 +4,7 @@ const config = require('wild-config');
const fs = require('fs');
const db = require('./db');
const CertHandler = require('./cert-handler');
const { buildCertChain } = require('./tools');
const certs = new Map();
const servers = [];
@ -92,12 +93,7 @@ module.exports.loadTLSOptions = (serverOptions, name) => {
if (serverCerts) {
serverOptions.key = serverCerts.key;
if (serverCerts.ca) {
serverOptions.ca = serverCerts.ca;
}
serverOptions.cert = serverCerts.cert;
serverOptions.cert = buildCertChain(serverCerts.cert, serverCerts.ca);
if (serverCerts.dhparam) {
serverOptions.dhparam = serverCerts.dhparam;
@ -130,13 +126,12 @@ config.on('reload', () => {
let certOptions = {};
if (serverCerts) {
certOptions.key = serverCerts.key;
if (serverCerts.ca) {
certOptions.ca = serverCerts.ca;
}
certOptions.cert = serverCerts.cert;
certOptions.cert = buildCertChain(serverCerts.cert, serverCerts.ca);
if (serverCerts.dhparam) {
certOptions.dhparam = serverCerts.dhparam;
}
entry.server.updateSecureContext(certOptions);
}
});

View file

@ -1,3 +1,4 @@
/* eslint no-control-regex: 0 */
'use strict';
const os = require('os');
@ -586,6 +587,24 @@ function roundTime(seconds) {
return `${seconds} ${seconds === 1 ? 'second' : 'seconds'}`;
}
function parsePemBundle(bundle) {
bundle = (bundle || '').toString().split(/\r?\n/).join('\x00');
let matches = bundle.match(/[-]{3,}BEGIN [^-]+[-]{3,}.*?[-]{3,}END [^-]+[-]{3,}/g);
if (matches) {
matches = Array.from(matches).map(cert => cert.replace(/\x00/g, '\n') + '\n');
}
return matches;
}
function buildCertChain(cert, ca) {
return [cert]
.concat(ca || [])
.flatMap(ca => ca)
.map(ca => ca.trim() + '\n')
.filter(ca => ca.trim())
.join('\n');
}
module.exports = {
normalizeAddress,
normalizeDomain,
@ -609,6 +628,8 @@ module.exports = {
formatFingerprint,
getEnabled2fa,
roundTime,
parsePemBundle,
buildCertChain,
formatMetaData: metaData => {
if (typeof metaData === 'string') {