Fix OpenSSL data parsing

OpenSSL data parsing could be confused when parsing certificates which
have Country/Org and other parameters in the subject line.

This is fixed by writing a more robust parser of the output lines, and
using that to do parsing which now correctly handles this case.
This commit is contained in:
Will Rouesnel
2023-05-24 23:59:38 +10:00
parent 2dd4434ceb
commit b19a272403

View File

@ -726,6 +726,28 @@ const internalCertificate = {
});
},
/**
* Parse the X509 subject line as returned by the OpenSSL command when
* invoked with openssl x509 -in <certificate name> -subject -noout
*
* @param {String} line emitted from the openssl command
* @param {String} prefix expected to be removed
* @return {Object} object containing the parsed fields from the subject line
*/
parseX509Output: (line, prefix) => {
// Remove the subject= part
const subject_value = line.slice(prefix.length);
const subject = subject_value.split(/,(?=(?:(?:[^"]*"){2})*[^"]*$)/)
.map( (e) => { return e.trim().split(' = ', 2); })
.reduce((obj, [key, value]) => {
obj[key] = value.replace(/^"/, '').replace(/"$/, '');
return obj;
}, {});
return subject;
},
/**
* Uses the openssl command to both validate and get info out of the certificate.
* It will save the file to disk first, then run commands on it, then delete the file.
@ -739,28 +761,27 @@ const internalCertificate = {
return utils.exec('openssl x509 -in ' + certificate_file + ' -subject -noout')
.then((result) => {
// subject=CN = something.example.com
const regex = /(?:subject=)?[^=]+=\s+(\S+)/gim;
const match = regex.exec(result);
// subject=C = NoCountry, O = NoOrg, OU = NoOrgUnit, CN = Some Value With Spaces
const subjectParams = internalCertificate.parseX509Output(result, 'subject=');
if (typeof match[1] === 'undefined') {
if (typeof subjectParams.CN === 'undefined') {
throw new error.ValidationError('Could not determine subject from certificate: ' + result);
}
certData['cn'] = match[1];
certData['cn'] = subjectParams.CN;
})
.then(() => {
return utils.exec('openssl x509 -in ' + certificate_file + ' -issuer -noout');
})
.then((result) => {
// issuer=C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3
const regex = /^(?:issuer=)?(.*)$/gim;
const match = regex.exec(result);
const issuerParams = internalCertificate.parseX509Output(result, 'issuer=');
if (typeof match[1] === 'undefined') {
if (typeof issuerParams.CN === 'undefined') {
throw new error.ValidationError('Could not determine issuer from certificate: ' + result);
}
certData['issuer'] = match[1];
certData['issuer'] = issuerParams.CN;
})
.then(() => {
return utils.exec('openssl x509 -in ' + certificate_file + ' -dates -noout');