Skip to content

Commit

Permalink
Improve public key extractor.
Browse files Browse the repository at this point in the history
Add a way for extract public key from DOM nodes.
  • Loading branch information
Maks3w committed Nov 5, 2013
1 parent 96b8d60 commit 16e3bd3
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 9 deletions.
12 changes: 11 additions & 1 deletion src/FR3D/XmlDSig/Adapter/AdapterInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace FR3D\XmlDSig\Adapter;

use DOMDocument;
use DOMNode;
use RuntimeException;

/**
Expand Down Expand Up @@ -56,9 +57,18 @@ public function setPrivateKey($privateKey, $algorithmType = self::RSA_SHA1);
public function setPublicKey($publicKey);

/**
* Returns the public key from various sources
*
* Try to get the public key from the following sources (index means priority):
*
* 1) From $dom param of this method
* 2) From a previous publickey set by setPublicKey
* 3) From private key set by setPrivateKey
*
* @param null|DOMNode $dom DOM node where to search a publicKey
* @return string|null Public key in PEM format
*/
public function getPublicKey();
public function getPublicKey(DOMNode $dom = null);

/**
* Public/Private key signature algorithm
Expand Down
59 changes: 53 additions & 6 deletions src/FR3D/XmlDSig/Adapter/XmlseclibsAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace FR3D\XmlDSig\Adapter;

use DOMDocument;
use DOMNode;
use XMLSecEnc;
use RuntimeException;
use XMLSecurityKey;
Expand Down Expand Up @@ -77,14 +78,14 @@ public function setPublicKey($publicKey)
return $this;
}

public function getPublicKey()
public function getPublicKey(DOMNode $dom = null)
{
if ($dom) {
$this->setPublicKeyFromNode($dom);
}

if (!$this->publicKey && $this->privateKey) {
// Extract public key from private key
openssl_pkey_export(
openssl_pkey_get_public($this->privateKey),
$this->publicKey
);
$this->setPublicKeyFromPrivateKey($this->privateKey);
}

return $this->publicKey;
Expand Down Expand Up @@ -191,4 +192,50 @@ public function verify(DOMDocument $data)

return true;
}

/**
* Try to extract the public key from DOM node
*
* Sets publicKey and keyAlgorithm properties if success.
*
* @see publicKey
* @see keyAlgorithm
* @param DOMNode $dom
* @return bool `true` If public key was extracted or `false` if cannot be possible
*/
protected function setPublicKeyFromNode(DOMNode $dom)
{
// try to get the public key from the certificate
$objXMLSecDSig = new XMLSecurityDSig();
$objDSig = $objXMLSecDSig->locateSignature($dom);
if (!$objDSig) {
return false;
}

$objKey = $objXMLSecDSig->locateKey();
if (!$objKey) {
return false;
}

XMLSecEnc::staticLocateKeyInfo($objKey, $objDSig);
$this->publicKey = $objKey->getX509Certificate();
$this->keyAlgorithm = $objKey->getAlgorith();

return true;
}

/**
* Try to extract the public key from private key
*
* @see publicKey
* @param string $privateKey
* @return bool `true` If public key was extracted or `false` if cannot be possible
*/
protected function setPublicKeyFromPrivateKey($privateKey)
{
return openssl_pkey_export(
openssl_pkey_get_public($privateKey),
$this->publicKey
);
}
}
42 changes: 40 additions & 2 deletions test/FR3D/XmlDSigTest/Adapter/CommonTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,34 @@ class CommonTestCase extends \PHPUnit_Framework_TestCase
*/
protected $publicKey = '../_files/pubkey.pem';

public function testGetPublicKeyFromSetter()
{
$publicKey = $this->getPublicKey();
$this->assertNotEquals($publicKey, $this->adapter->getPublicKey());

$this->adapter->setPublicKey($publicKey);
$this->assertEquals($publicKey, $this->adapter->getPublicKey());
}

public function testGetPublicKeyFromPrivateKey()
{
$publicKey = $this->getPublicKey();
$this->assertNotEquals($publicKey, $this->adapter->getPublicKey());

$this->adapter->setPrivateKey($this->getPrivateKey());
$this->assertEquals($publicKey, $this->adapter->getPublicKey());
}

public function testGetPublicKeyFromNode()
{
$publicKey = $this->getPublicKey();
$this->assertNotEquals($publicKey, $this->adapter->getPublicKey());

$data = new DOMDocument();
$data->load(__DIR__ . '/_files/basic-doc-signed.xml');
$this->assertEquals($publicKey, $this->adapter->getPublicKey($data));
}

public function testSignWithoutPrivateKeys()
{
$this->setExpectedException(
Expand All @@ -41,8 +69,8 @@ public function testSign()
$data->load(__DIR__ . '/_files/basic-doc.xml');

$this->adapter
->setPrivateKey(file_get_contents(__DIR__ . '/' . $this->privateKey))
->setPublicKey(file_get_contents(__DIR__ . '/' . $this->publicKey))
->setPrivateKey($this->getPrivateKey())
->setPublicKey($this->getPublicKey())
->addTransform(AdapterInterface::ENVELOPED)
->setCanonicalMethod('http://www.w3.org/2001/10/xml-exc-c14n#')
->sign($data);
Expand Down Expand Up @@ -84,4 +112,14 @@ public function testManipulatedSignature()

$this->assertFalse($this->adapter->verify($data));
}

protected function getPrivateKey()
{
return file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . $this->privateKey);
}

protected function getPublicKey()
{
return file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . $this->publicKey);
}
}
5 changes: 5 additions & 0 deletions test/FR3D/XmlDSigTest/Adapter/XmlseclibsAdapterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,9 @@ protected function setUp()
{
$this->adapter = new XmlseclibsAdapter();
}

public function testGetPublicKeyFromPrivateKey()
{
$this->markTestIncomplete('PHP OpenSSL extension does not extract public key from private key');
}
}

0 comments on commit 16e3bd3

Please sign in to comment.