feat(ssl): improve SSL generation and security a lot
- rename some variables for better clarity - format subjectAltNames correctly - setup extensions more securely and improve them a lot - use finally block to remove tempConfig
This commit is contained in:
@@ -10,9 +10,9 @@ class SslHelper
|
|||||||
{
|
{
|
||||||
private const DEFAULT_ORGANIZATION_NAME = 'Coolify';
|
private const DEFAULT_ORGANIZATION_NAME = 'Coolify';
|
||||||
|
|
||||||
private const DEFAULT_COUNTRY_CODE = 'ZZ';
|
private const DEFAULT_COUNTRY_NAME = 'ZZ';
|
||||||
|
|
||||||
private const DEFAULT_STATE = 'Default';
|
private const DEFAULT_STATE_NAME = 'Default';
|
||||||
|
|
||||||
public static function generateSslCertificate(
|
public static function generateSslCertificate(
|
||||||
string $commonName,
|
string $commonName,
|
||||||
@@ -27,6 +27,9 @@ class SslHelper
|
|||||||
?string $configurationDir = null,
|
?string $configurationDir = null,
|
||||||
?string $mountPath = null
|
?string $mountPath = null
|
||||||
): SslCertificate {
|
): SslCertificate {
|
||||||
|
$organizationName = self::DEFAULT_ORGANIZATION_NAME;
|
||||||
|
$countryName = self::DEFAULT_COUNTRY_NAME;
|
||||||
|
$stateName = self::DEFAULT_STATE_NAME;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$privateKey = openssl_pkey_new([
|
$privateKey = openssl_pkey_new([
|
||||||
@@ -60,41 +63,42 @@ class SslHelper
|
|||||||
array_merge(["DNS:$commonName"], $subjectAlternativeNames)
|
array_merge(["DNS:$commonName"], $subjectAlternativeNames)
|
||||||
);
|
);
|
||||||
|
|
||||||
$countryCode = self::DEFAULT_COUNTRY_CODE;
|
$formattedSubjectAltNames = [];
|
||||||
$state = self::DEFAULT_STATE;
|
|
||||||
$organization = self::DEFAULT_ORGANIZATION_NAME;
|
|
||||||
|
|
||||||
$altNames = [];
|
|
||||||
foreach ($subjectAlternativeNames as $index => $san) {
|
foreach ($subjectAlternativeNames as $index => $san) {
|
||||||
[$type, $value] = explode(':', $san, 2);
|
[$type, $value] = explode(':', $san, 2);
|
||||||
$altNames[] = "{$type}.".($index + 1)." = $value";
|
$formattedSubjectAltNames[] = "{$type}.".($index + 1)." = $value";
|
||||||
}
|
}
|
||||||
$altNamesSection = implode("\n", $altNames);
|
$formattedSubjectAltNamesSection = implode("\n", $formattedSubjectAltNames);
|
||||||
|
|
||||||
$basicConstraints = $isCaCertificate ? 'CA:TRUE' : 'CA:FALSE';
|
$basicConstraints = $isCaCertificate ? 'critical, CA:TRUE, pathlen:0' : 'critical, CA:FALSE';
|
||||||
$keyUsage = $isCaCertificate ? 'keyCertSign, cRLSign' : 'digitalSignature, keyEncipherment';
|
$keyUsage = $isCaCertificate ? 'critical, keyCertSign, cRLSign' : 'critical, digitalSignature';
|
||||||
$extendedKeyUsage = $isCaCertificate ? '' : 'extendedKeyUsage = serverAuth';
|
$authorityKeyIdentifierLine = $isCaCertificate ? '' : "authorityKeyIdentifier = critical,keyid,issuer\n";
|
||||||
|
|
||||||
$config = <<<CONF
|
$config = <<<CONF
|
||||||
[req]
|
[req]
|
||||||
prompt = no
|
prompt = no
|
||||||
distinguished_name = req_distinguished_name
|
distinguished_name = distinguished_name
|
||||||
req_extensions = v3_req
|
req_extensions = req_ext
|
||||||
|
|
||||||
[req_distinguished_name]
|
[distinguished_name]
|
||||||
C = $countryCode
|
C = $countryName
|
||||||
ST = $state
|
ST = $stateName
|
||||||
O = $organization
|
O = $organizationName
|
||||||
CN = $commonName
|
CN = $commonName
|
||||||
|
|
||||||
|
[req_ext]
|
||||||
|
basicConstraints = $basicConstraints
|
||||||
|
keyUsage = $keyUsage
|
||||||
|
|
||||||
[v3_req]
|
[v3_req]
|
||||||
basicConstraints = $basicConstraints
|
basicConstraints = $basicConstraints
|
||||||
keyUsage = $keyUsage
|
keyUsage = $keyUsage
|
||||||
$extendedKeyUsage
|
subjectKeyIdentifier = critical,hash
|
||||||
subjectAltName = @alt_names
|
{$authorityKeyIdentifierLine}
|
||||||
|
subjectAltName = critical,@subject_alt_names
|
||||||
|
|
||||||
[alt_names]
|
[subject_alt_names]
|
||||||
$altNamesSection
|
$formattedSubjectAltNamesSection
|
||||||
CONF;
|
CONF;
|
||||||
|
|
||||||
$tempConfig = tmpfile();
|
$tempConfig = tmpfile();
|
||||||
@@ -103,13 +107,13 @@ class SslHelper
|
|||||||
|
|
||||||
$csr = openssl_csr_new([
|
$csr = openssl_csr_new([
|
||||||
'commonName' => $commonName,
|
'commonName' => $commonName,
|
||||||
'organizationName' => self::DEFAULT_ORGANIZATION_NAME,
|
'organizationName' => $organizationName,
|
||||||
'countryName' => self::DEFAULT_COUNTRY_CODE,
|
'countryName' => $countryName,
|
||||||
'stateOrProvinceName' => self::DEFAULT_STATE,
|
'stateOrProvinceName' => $stateName,
|
||||||
], $privateKey, [
|
], $privateKey, [
|
||||||
'digest_alg' => 'sha512',
|
'digest_alg' => 'sha512',
|
||||||
'config' => $tempConfigPath,
|
'config' => $tempConfigPath,
|
||||||
'encrypt_key' => false,
|
'req_extensions' => 'req_ext',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if ($csr === false) {
|
if ($csr === false) {
|
||||||
@@ -194,11 +198,11 @@ class SslHelper
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose($tempConfig);
|
|
||||||
|
|
||||||
return $sslCertificate;
|
return $sslCertificate;
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
throw new \RuntimeException('SSL Certificate generation failed: '.$e->getMessage(), 0, $e);
|
throw new \RuntimeException('SSL Certificate generation failed: '.$e->getMessage(), 0, $e);
|
||||||
|
} finally {
|
||||||
|
fclose($tempConfig);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user