Skip to content

Commit

Permalink
Add support for additional CA certificate when S/MIME signing, fixes P…
Browse files Browse the repository at this point in the history
  • Loading branch information
Synchro committed Mar 6, 2015
1 parent ec94520 commit c506185
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 4 deletions.
1 change: 1 addition & 0 deletions .gitignore
@@ -1,5 +1,6 @@
docs/phpdoc/
test/message.txt
test/testbootstrap.php
test/*.pem
.idea
build/
15 changes: 13 additions & 2 deletions class.phpmailer.php
Expand Up @@ -536,6 +536,13 @@ class PHPMailer
*/
protected $sign_key_file = '';

/**
* The optional S/MIME extra certificates ("CA Chain") file path.
* @type string
* @access protected
*/
protected $sign_extracerts_file = '';

/**
* The S/MIME password for the key.
* Used only if the key is encrypted.
Expand Down Expand Up @@ -1971,7 +1978,9 @@ public function createBody()
$signed,
'file://' . realpath($this->sign_cert_file),
array('file://' . realpath($this->sign_key_file), $this->sign_key_pass),
null
null,
PKCS7_DETACHED,
$this->sign_extracerts_file
)
) {
@unlink($file);
Expand Down Expand Up @@ -3244,12 +3253,14 @@ public static function normalizeBreaks($text, $breaktype = "\r\n")
* @param string $cert_filename
* @param string $key_filename
* @param string $key_pass Password for private key
* @param string $extracerts_filename Optional path to chain certificate
*/
public function sign($cert_filename, $key_filename, $key_pass)
public function sign($cert_filename, $key_filename, $key_pass, $extracerts_filename = '')
{
$this->sign_cert_file = $cert_filename;
$this->sign_key_file = $key_filename;
$this->sign_key_pass = $key_pass;
$this->sign_extracerts_file = $extracerts_filename;
}

/**
Expand Down
91 changes: 89 additions & 2 deletions test/phpmailerTest.php
Expand Up @@ -1260,7 +1260,7 @@ public function testBase64()
$this->assertTrue($this->Mail->send(), 'Base64 encoding failed');
}
/**
* S/MIME Signing tests.
* S/MIME Signing tests (self-signed).
*/
public function testSigning()
{
Expand All @@ -1277,12 +1277,17 @@ public function testSigning()
'commonName' => 'PHPMailer Test',
'emailAddress' => 'phpmailer@example.com'
);
$keyconfig = array(
"digest_alg" => "sha256",
"private_key_bits" => 2048,
"private_key_type" => OPENSSL_KEYTYPE_RSA,
);
$password = 'password';
$certfile = 'certfile.txt';
$keyfile = 'keyfile.txt';

//Make a new key pair
$pk = openssl_pkey_new();
$pk = openssl_pkey_new($keyconfig);
//Create a certificate signing request
$csr = openssl_csr_new($dn, $pk);
//Create a self-signed cert
Expand All @@ -1304,6 +1309,88 @@ public function testSigning()
unlink($keyfile);
}

/**
* S/MIME Signing tests using a CA chain cert.
* To test that a generated message is signed correctly, save the message in a file
* and use openssl along with the certs generated by this script:
* `openssl smime -verify -in signed.eml -signer certfile.pem -CAfile cacertfile.pem`
*/
public function testSigningWithCA()
{
$this->Mail->Subject .= ': S/MIME signing with CA';
$this->Mail->Body = 'This message is S/MIME signed with an extra CA cert.';
$this->buildBody();

$certprops = array(
'countryName' => 'UK',
'stateOrProvinceName' => 'Here',
'localityName' => 'There',
'organizationName' => 'PHP',
'organizationalUnitName' => 'PHPMailer',
'commonName' => 'PHPMailer Test',
'emailAddress' => 'phpmailer@example.com'
);
$cacertprops = array(
'countryName' => 'UK',
'stateOrProvinceName' => 'Here',
'localityName' => 'There',
'organizationName' => 'PHP',
'organizationalUnitName' => 'PHPMailer CA',
'commonName' => 'PHPMailer Test CA',
'emailAddress' => 'phpmailer@example.com'
);
$keyconfig = array(
"digest_alg" => "sha256",
"private_key_bits" => 2048,
"private_key_type" => OPENSSL_KEYTYPE_RSA,
);
$password = 'password';
$cacertfile = 'cacertfile.pem';
$cakeyfile = 'cakeyfile.pem';
$certfile = 'certfile.pem';
$keyfile = 'keyfile.pem';

//Create a CA cert
//Make a new key pair
$capk = openssl_pkey_new($keyconfig);
//Create a certificate signing request
$csr = openssl_csr_new($cacertprops, $capk);
//Create a self-signed cert
$cert = openssl_csr_sign($csr, null, $capk, 1);
//Save the CA cert
openssl_x509_export($cert, $certout);
file_put_contents($cacertfile, $certout);
//Save the CA key
openssl_pkey_export($capk, $pkeyout, $password);
file_put_contents($cakeyfile, $pkeyout);

//Create a cert signed by our CA
//Make a new key pair
$pk = openssl_pkey_new($keyconfig);
//Create a certificate signing request
$csr = openssl_csr_new($certprops, $pk);
//Create a self-signed cert
$cert = openssl_csr_sign($csr, 'file://' . $cacertfile, $capk, 1);
//Save the cert
openssl_x509_export($cert, $certout);
file_put_contents($certfile, $certout);
//Save the key
openssl_pkey_export($pk, $pkeyout, $password);
file_put_contents($keyfile, $pkeyout);

$this->Mail->sign(
$certfile,
$keyfile,
$password,
$cacertfile
);
$this->assertTrue($this->Mail->send(), 'S/MIME signing with CA failed');
unlink($cacertfile);
unlink($cakeyfile);
unlink($certfile);
unlink($keyfile);
}

/**
* DKIM Signing tests.
*/
Expand Down

0 comments on commit c506185

Please sign in to comment.