Skip to content

Commit 6bb56fe

Browse files
authored
Change openssl_x509_verify test to use cert generator (#17882)
This also prevents verifying cert with SHA1 signature
1 parent 422e90d commit 6bb56fe

File tree

2 files changed

+70
-38
lines changed

2 files changed

+70
-38
lines changed

ext/openssl/tests/CertificateGenerator.inc

+53-34
Original file line numberDiff line numberDiff line change
@@ -4,26 +4,33 @@ class CertificateGenerator
44
{
55
const CONFIG = __DIR__. DIRECTORY_SEPARATOR . 'openssl.cnf';
66

7-
/** @var OpenSSLCertificate */
8-
private $ca;
7+
/** @var OpenSSLCertificate|false */
8+
private $ca = false;
99

10-
/** @var resource */
11-
private $caKey;
10+
/** @var OpenSSLAsymmetricKey|false */
11+
private $caKey = false;
1212

13-
/** @var resource|null */
13+
/** @var bool */
14+
private $useSelfSignedCert;
15+
16+
/** @var OpenSSLCertificate|null */
1417
private $lastCert;
1518

16-
/** @var resource|null */
19+
/** @var OpenSSLAsymmetricKey|null */
1720
private $lastKey;
1821

19-
public function __construct()
22+
public function __construct(bool $useSelfSignedCert = false)
2023
{
2124
if (!extension_loaded('openssl')) {
2225
throw new RuntimeException(
2326
'openssl extension must be loaded to generate certificates'
2427
);
2528
}
26-
$this->generateCa();
29+
$this->useSelfSignedCert = $useSelfSignedCert;
30+
31+
if (!$this->useSelfSignedCert) {
32+
$this->generateCa();
33+
}
2734
}
2835

2936
/**
@@ -54,40 +61,32 @@ class CertificateGenerator
5461
'commonName' => 'CA for PHP Tests'
5562
];
5663

57-
$this->ca = openssl_csr_sign(
58-
openssl_csr_new(
59-
$dn,
60-
$this->caKey,
61-
[
62-
'x509_extensions' => 'v3_ca',
63-
'config' => self::CONFIG,
64-
]
65-
),
66-
null,
67-
$this->caKey,
68-
2,
69-
[
70-
'config' => self::CONFIG,
71-
]
72-
);
64+
$csr = openssl_csr_new($dn, $this->caKey, ['config' => self::CONFIG]);
65+
$this->ca = openssl_csr_sign($csr, null, $this->caKey, 365, ['config' => self::CONFIG]);
7366
}
7467

7568
public function getCaCert()
7669
{
70+
if ($this->useSelfSignedCert) {
71+
throw new RuntimeException("CA is not generated in self-signed mode.");
72+
}
73+
7774
$output = '';
7875
openssl_x509_export($this->ca, $output);
79-
8076
return $output;
8177
}
8278

8379
public function saveCaCert($file)
8480
{
81+
if ($this->useSelfSignedCert) {
82+
throw new RuntimeException("CA is not available in self-signed mode.");
83+
}
84+
8585
openssl_x509_export_to_file($this->ca, $file);
8686
}
8787

88-
private function generateCertAndKey(
89-
$commonNameForCert, $file, $keyLength = null, $subjectAltName = null
90-
) {
88+
private function generateCertAndKey($commonNameForCert, $file, $keyLength = null, $subjectAltName = null)
89+
{
9190
$dn = [
9291
'countryName' => 'BY',
9392
'stateOrProvinceName' => 'Minsk',
@@ -98,8 +97,7 @@ class CertificateGenerator
9897
$dn['commonName'] = $commonNameForCert;
9998
}
10099

101-
$subjectAltNameConfig =
102-
$subjectAltName ? "subjectAltName = $subjectAltName" : "";
100+
$subjectAltNameConfig = $subjectAltName ? "subjectAltName = $subjectAltName" : "";
103101
$configCode = <<<CONFIG
104102
[ req ]
105103
distinguished_name = req_distinguished_name
@@ -128,12 +126,17 @@ CONFIG;
128126

129127
$this->lastKey = self::generateKey($keyLength);
130128
$csr = openssl_csr_new($dn, $this->lastKey, $config);
129+
130+
// If in self-signed mode, sign with the same key, otherwise use CA
131+
$signingCert = $this->useSelfSignedCert ? null : $this->ca;
132+
$signingKey = $this->useSelfSignedCert ? $this->lastKey : $this->caKey;
133+
131134
$this->lastCert = openssl_csr_sign(
132135
$csr,
133-
$this->ca,
134-
$this->caKey,
135-
/* days */ 2,
136-
$config,
136+
$signingCert,
137+
$signingKey,
138+
365, // 1 year validity
139+
$config
137140
);
138141

139142
return $config;
@@ -166,6 +169,22 @@ CONFIG;
166169
unlink($config['config']);
167170
}
168171

172+
public function saveNewCertAndPubKey(
173+
$commonNameForCert, $certFile, $pubKeyFile, $keyLength = null, $subjectAltName = null
174+
) {
175+
$config = $this->generateCertAndKey($commonNameForCert, $certFile, $keyLength, $subjectAltName);
176+
177+
openssl_x509_export_to_file($this->lastCert, $certFile);
178+
179+
$keyDetails = openssl_pkey_get_details($this->lastKey);
180+
if ($keyDetails === false || !isset($keyDetails['key'])) {
181+
throw new RuntimeException("Failed to extract public key.");
182+
}
183+
184+
file_put_contents($pubKeyFile, $keyDetails['key']);
185+
unlink($config['config']);
186+
}
187+
169188
public function getCertDigest($algo)
170189
{
171190
return openssl_x509_fingerprint($this->lastCert, $algo);

ext/openssl/tests/openssl_x509_verify.phpt

+17-4
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,24 @@ openssl_x509_verify() tests
44
openssl
55
--FILE--
66
<?php
7-
$fp = fopen(__DIR__ . "/cert.crt","r");
7+
8+
$certFile = __DIR__ . '/openssl-x509-verify-cert.pem.tmp';
9+
$keyFile = __DIR__ . '/openssl-x509-verify-key.pem.tmp';
10+
11+
include 'CertificateGenerator.inc';
12+
$certificateGenerator = new CertificateGenerator(true);
13+
$certificateGenerator->saveNewCertAndPubKey('openssl-x509-verify-server', $certFile, $keyFile);
14+
15+
$fp = fopen($certFile,"r");
816
$a = fread($fp, 8192);
917
fclose($fp);
1018

11-
$fp = fopen(__DIR__ . "/public.key","r");
19+
$fp = fopen($keyFile,"r");
1220
$b = fread($fp, 8192);
1321
fclose($fp);
1422

15-
$cert = "file://" . __DIR__ . "/cert.crt";
16-
$key = "file://" . __DIR__ . "/public.key";
23+
$cert = "file://" . $certFile;
24+
$key = "file://" . $keyFile;
1725
$wrongKey = "file://" . __DIR__ . "/public_rsa_2048.key";
1826

1927
var_dump(openssl_x509_verify($cert, $key));
@@ -23,6 +31,11 @@ var_dump(openssl_x509_verify("", ""));
2331
var_dump(openssl_x509_verify(openssl_x509_read($a), $b));
2432
var_dump(openssl_x509_verify($cert, $wrongKey));
2533
?>
34+
--CLEAN--
35+
<?php
36+
@unlink(__DIR__ . '/openssl-x509-verify-cert.pem.tmp');
37+
@unlink(__DIR__ . '/openssl-x509-verify-key.pem.tmp');
38+
?>
2639
--EXPECT--
2740
int(1)
2841
int(-1)

0 commit comments

Comments
 (0)