Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 5 additions & 82 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,85 +1,8 @@
#xmlseclibs
# Fork of robrichards/xmlseclibs for eID-Templates

xmlseclibs is a library written in PHP for working with XML Encryption and Signatures.
This is a fork of [robrichards/xmlseclibs](https://github.com/robrichards/xmlseclibs/), which has been created to make the library match the needs of the eID-Templates project.

The author of xmlseclibs is Rob Richards.
The main changes are:
* Support for RSASSA-PSS based XML signature algorithms via usage of the RSA implementation of [phpseclib])http://phpseclib.sourceforge.net/)

# Branches
Master is currently the only actively maintained branch.
* master/3.1: Added AES-GCM support requiring 7.1+
* 3.0: Removes mcrypt usage requiring 5.4+ (5.6.24+ recommended for security reasons)
* 2.0: Contains namespace support requiring 5.3+
* 1.4: Contains auto-loader support while also maintaining backwards compatiblity with the older 1.3 version using the xmlseclibs.php file. Supports PHP 5.2+

# Requirements

xmlseclibs requires PHP version 5.4 or greater. **5.6.24+ recommended for security reasons**


## How to Install

Install with [`composer.phar`](http://getcomposer.org).

```sh
php composer.phar require "robrichards/xmlseclibs"
```


## Use cases

xmlseclibs is being used in many different software.

* [SimpleSAMLPHP](https://github.com/simplesamlphp/simplesamlphp)
* [LightSAML](https://github.com/lightsaml/lightsaml)
* [OneLogin](https://github.com/onelogin/php-saml)

## Basic usage

The example below shows basic usage of xmlseclibs, with a SHA-256 signature.

```php
use RobRichards\XMLSecLibs\XMLSecurityDSig;
use RobRichards\XMLSecLibs\XMLSecurityKey;

// Load the XML to be signed
$doc = new DOMDocument();
$doc->load('./path/to/file/tobesigned.xml');

// Create a new Security object
$objDSig = new XMLSecurityDSig();
// Use the c14n exclusive canonicalization
$objDSig->setCanonicalMethod(XMLSecurityDSig::EXC_C14N);
// Sign using SHA-256
$objDSig->addReference(
$doc,
XMLSecurityDSig::SHA256,
array('http://www.w3.org/2000/09/xmldsig#enveloped-signature')
);

// Create a new (private) Security key
$objKey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA256, array('type'=>'private'));
/*
If key has a passphrase, set it using
$objKey->passphrase = '<passphrase>';
*/
// Load the private key
$objKey->loadKey('./path/to/privatekey.pem', TRUE);

// Sign the XML file
$objDSig->sign($objKey);

// Add the associated public key to the signature
$objDSig->add509Cert(file_get_contents('./path/to/file/mycert.pem'));

// Append the signature to the XML
$objDSig->appendSignature($doc->documentElement);
// Save the signed XML
$doc->save('./path/to/signed.xml');
```

## How to Contribute

* [Open Issues](https://github.com/robrichards/xmlseclibs/issues)
* [Open Pull Requests](https://github.com/robrichards/xmlseclibs/pulls)

Mailing List: https://groups.google.com/forum/#!forum/xmlseclibs
Please refer to the upstream`s [readme](https://github.com/robrichards/xmlseclibs/blob/master/README.md) for further information.
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
},
"require": {
"php": ">= 5.4",
"ext-openssl": "*"
"ext-openssl": "*",
"phpseclib/phpseclib": "~2.0"
}
}
4 changes: 4 additions & 0 deletions src/XMLSecurityDSig.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ class XMLSecurityDSig
{
const XMLDSIGNS = 'http://www.w3.org/2000/09/xmldsig#';
const SHA1 = 'http://www.w3.org/2000/09/xmldsig#sha1';
const SHA224 = 'https://www.w3.org/2001/04/xmldsig-more#sha224';
const SHA256 = 'http://www.w3.org/2001/04/xmlenc#sha256';
const SHA384 = 'http://www.w3.org/2001/04/xmldsig-more#sha384';
const SHA512 = 'http://www.w3.org/2001/04/xmlenc#sha512';
Expand Down Expand Up @@ -349,6 +350,9 @@ public function calculateDigest($digestAlgorithm, $data, $encode = true)
case self::SHA1:
$alg = 'sha1';
break;
case self::SHA224:
$alg = 'sha224';
break;
case self::SHA256:
$alg = 'sha256';
break;
Expand Down
147 changes: 147 additions & 0 deletions src/XMLSecurityKey.php
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
<?php
namespace RobRichards\XMLSecLibs;

if (file_exists(__DIR__ . '/../vendor/autoload.php')) {
require __DIR__ . '/../vendor/autoload.php';
}

use DOMElement;
use Exception;
use phpseclib\Crypt\RSA;
use phpseclib\File\X509;

/**
* xmlseclibs.php
Expand Down Expand Up @@ -61,6 +67,11 @@ class XMLSecurityKey
const RSA_SHA256 = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256';
const RSA_SHA384 = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha384';
const RSA_SHA512 = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha512';
const SHA1_RSA_MGF1 = 'http://www.w3.org/2007/05/xmldsig-more#sha1-rsa-MGF1';
const SHA224_RSA_MGF1 = 'http://www.w3.org/2007/05/xmldsig-more#sha224-rsa-MGF1';
const SHA256_RSA_MGF1 = 'http://www.w3.org/2007/05/xmldsig-more#sha256-rsa-MGF1';
const SHA384_RSA_MGF1 = 'http://www.w3.org/2007/05/xmldsig-more#sha384-rsa-MGF1';
const SHA512_RSA_MGF1 = 'http://www.w3.org/2007/05/xmldsig-more#sha512-rsa-MGF1';
const HMAC_SHA1 = 'http://www.w3.org/2000/09/xmldsig#hmac-sha1';
const AUTHTAG_LENGTH = 16;

Expand Down Expand Up @@ -253,6 +264,60 @@ public function __construct($type, $params=null)
}
}
throw new Exception('Certificate "type" (private/public) must be passed via parameters');
case (self::SHA1_RSA_MGF1):
$this->cryptParams['library'] = 'phpseclib';
$this->cryptParams['method'] = 'http://www.w3.org/2007/05/xmldsig-more#sha1-rsa-MGF1';
$this->cryptParams['digest'] = 'sha1';
if (is_array($params) && ! empty($params['type'])) {
if ($params['type'] == 'public' || $params['type'] == 'private') {
$this->cryptParams['type'] = $params['type'];
break;
}
}
case (self::SHA224_RSA_MGF1):
$this->cryptParams['library'] = 'phpseclib';
$this->cryptParams['method'] = 'http://www.w3.org/2007/05/xmldsig-more#sha224-rsa-MGF1';
$this->cryptParams['digest'] = 'sha224';
if (is_array($params) && ! empty($params['type'])) {
if ($params['type'] == 'public' || $params['type'] == 'private') {
$this->cryptParams['type'] = $params['type'];
break;
}
}
throw new Exception('Certificate "type" (private/public) must be passed via parameters');
case (self::SHA256_RSA_MGF1):
$this->cryptParams['library'] = 'phpseclib';
$this->cryptParams['method'] = 'http://www.w3.org/2007/05/xmldsig-more#sha256-rsa-MGF1';
$this->cryptParams['digest'] = 'sha256';
if (is_array($params) && ! empty($params['type'])) {
if ($params['type'] == 'public' || $params['type'] == 'private') {
$this->cryptParams['type'] = $params['type'];
break;
}
}
throw new Exception('Certificate "type" (private/public) must be passed via parameters');
case (self::SHA384_RSA_MGF1):
$this->cryptParams['library'] = 'phpseclib';
$this->cryptParams['method'] = 'http://www.w3.org/2007/05/xmldsig-more#sha384-rsa-MGF1';
$this->cryptParams['digest'] = 'sha384';
if (is_array($params) && ! empty($params['type'])) {
if ($params['type'] == 'public' || $params['type'] == 'private') {
$this->cryptParams['type'] = $params['type'];
break;
}
}
throw new Exception('Certificate "type" (private/public) must be passed via parameters');
case (self::SHA512_RSA_MGF1):
$this->cryptParams['library'] = 'phpseclib';
$this->cryptParams['method'] = 'http://www.w3.org/2007/05/xmldsig-more#sha512-rsa-MGF1';
$this->cryptParams['digest'] = 'sha512';
if (is_array($params) && ! empty($params['type'])) {
if ($params['type'] == 'public' || $params['type'] == 'private') {
$this->cryptParams['type'] = $params['type'];
break;
}
}
throw new Exception('Certificate "type" (private/public) must be passed via parameters');
case (self::HMAC_SHA1):
$this->cryptParams['library'] = $type;
$this->cryptParams['method'] = 'http://www.w3.org/2000/09/xmldsig#hmac-sha1';
Expand Down Expand Up @@ -396,6 +461,27 @@ public function loadKey($key, $isFile=false, $isCert = false)
throw new Exception('Unknown type');
}
}
if ($this->cryptParams['library'] == 'phpseclib') {
switch ($this->cryptParams['type']) {
case 'public':
$rsa = new RSA();
if ($isCert) {
$x509 = new X509();
$x509->loadX509($this->key);
$this->key = $x509->getPublicKey();
}
$rsa->loadKey($this->key);
$this->key = $rsa;
break;
case 'private':
$rsa = new RSA();
$rsa->loadKey($this->key);
$this->key = $rsa;
break;
default:
throw new Exception('Unknown type');
}
}
}

/**
Expand Down Expand Up @@ -566,6 +652,32 @@ private function signOpenSSL($data)
return $signature;
}

/**
* Signs the given data (string) using phpSecLib
*
* @param string $data
* @return string
* @throws Exception
*/
private function signPhpSecLib($data)
{
if (empty($this->cryptParams['digest'])) {
throw new Exception('digest algo is not set');
}
if (empty($this->key)) {
throw new Exception('key not set');
}
$rsa = new RSA();
$rsa->loadKey($this->key);
$rsa->setHash($this->cryptParams['digest']);
$rsa->setMGFHash($this->cryptParams['digest']);
$signature = $rsa->sign($data);
if (!$signature) {
throw new Exception('Failure Signing Data: - ' . $this->cryptParams['digest']);
}
return $signature;
}

/**
* Verifies the given data (string) belonging to the given signature using the openssl-extension
*
Expand All @@ -591,6 +703,37 @@ private function verifyOpenSSL($data, $signature)
return openssl_verify($data, $signature, $this->key, $algo);
}

/**
* Verifies the given data (string) belonging to the given signature using phpseclib
*
* Returns:
* 1 on succesful signature verification,
* 0 when signature verification failed,
*
* @param string $data
* @param string $signature
* @return int
*/
private function verifyPhpSecLib($data, $signature)
{
if (empty($this->cryptParams['digest'])) {
throw new Exception('digest algo is not set');
}
if (empty($this->key)) {
throw new Exception('key not set');
}
$rsa = new RSA();
$rsa->loadKey($this->key);
$rsa->setHash($this->cryptParams['digest']);
$rsa->setMGFHash($this->cryptParams['digest']);
$verified = $rsa->verify($data, $signature);
if ($verified) {
return 1;
} else {
return 0;
}
}

/**
* Encrypts the given data (string) using the regarding php-extension, depending on the library assigned to algorithm in the contructor.
*
Expand Down Expand Up @@ -644,6 +787,8 @@ public function signData($data)
return $this->signOpenSSL($data);
case (self::HMAC_SHA1):
return hash_hmac("sha1", $data, $this->key, true);
case 'phpseclib':
return $this->signPhpSecLib($data);
}
}

Expand Down Expand Up @@ -671,6 +816,8 @@ public function verifySignature($data, $signature)
case (self::HMAC_SHA1):
$expectedSignature = hash_hmac("sha1", $data, $this->key, true);
return strcmp($signature, $expectedSignature) == 0;
case 'phpseclib':
return $this->verifyPhpSecLib($data, $signature);
}
}

Expand Down
9 changes: 9 additions & 0 deletions tests/pubkey.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA7bXTMjOSElQ9VM/gRwD6
8VSejdXmaJ34NwzL2VU9GcuuPqnF4/M7hwupaJQ7Hxpw/C1Lba2kO6gi/mxyqbPo
YwIQkXceVnJ+Ig65RacRS+yDZ6+r3pM7AkOOQT1K75LBfRSmu8l+IkgwbrZj36E9
eID5yLknvGOVHhnui5OrBdFoB8i/iZsTrt++yroWodqV2dfs+1eCSJTYHpibSpaq
74BnrhPU2oHxh1C/QbmSuX1Mf0Ug1I6sVHilN337fXxiAGZdHXborQtjrb+Ha9YM
S61JiPmWe+RZrXykE+0pkvdkFSNgeVgD5S9W5274ZGYssO5xRPkP8BidpshOESBY
3QIDAQAB
-----END PUBLIC KEY-----
Loading