PHPackages                             robrichards/xmlseclibs - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Security](/categories/security)
4. /
5. robrichards/xmlseclibs

ActiveLibrary[Security](/categories/security)

robrichards/xmlseclibs
======================

A PHP library for XML Security

3.1.5(5mo ago)41186.5M↓26.5%189[37 issues](https://github.com/robrichards/xmlseclibs/issues)[14 PRs](https://github.com/robrichards/xmlseclibs/pulls)20BSD-3-ClausePHPPHP &gt;= 5.4CI passing

Since May 21Pushed 1w ago26 watchersCompare

[ Source](https://github.com/robrichards/xmlseclibs)[ Packagist](https://packagist.org/packages/robrichards/xmlseclibs)[ Docs](https://github.com/robrichards/xmlseclibs)[ RSS](/packages/robrichards-xmlseclibs/feed)WikiDiscussions master Synced 2w ago

READMEChangelog (10)DependenciesVersions (35)Used By (20)Security (4)

\#xmlseclibs

xmlseclibs is a library written in PHP for working with XML Encryption and Signatures.

The author of xmlseclibs is Rob Richards.

Branches
========

[](#branches)

Master is currently the only actively maintained branch.

- master: requires PHP version 8.0+
- 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
============

[](#requirements)

xmlseclibs requires PHP version 8.0 or greater. OpenSSL is optional (phpseclib is used for crypto).

Security notes
--------------

[](#security-notes)

- Prefer the safe-by-default verifier `verifyDocument()` (see below). It requires a caller-supplied (pinned) key, never derives the key from the document's `KeyInfo`, enforces an algorithm allowlist for both the `SignatureMethod` and every `DigestMethod`, and only reports success when every reference validated. It returns the validated nodes for you to operate on.
- If you use the low-level primitives directly, always check verification with a strict comparison: `$objDSig->verify($key) === 1`. A return of `-1` is an error and is truthy in boolean context.
- After `validateReference()`, use `getValidatedNodes()` and operate only on those nodes (especially for SAML / WS-Security). Do not re-select assertions by Id from the whole document.
- Do not trust a signing certificate from `KeyInfo` alone. Load and pin trusted keys yourself.
- By default `verifyDocument()` accepts only SHA-256/384/512 digests and RSA-SHA-256/384/512 (and RSA-PSS) signatures. To interoperate with legacy peers, widen the sets explicitly, e.g. `$objDSig->allowedSignatureAlgorithms[] = XMLSecurityKey::RSA_SHA1;`.
- Prefer RSA-OAEP and AES-GCM for encryption. RSA-1.5 key transport is **denied by default** on decryption (Bleichenbacher risk); opt in with `$objenc->allowRSA15KeyTransport = true;` only for legacy interop. You can additionally pin exact algorithms via `$objenc->allowedKeyAlgorithms` / `$objenc->allowedDataAlgorithms` (presets: `XMLSecEnc::DEFAULT_KEY_ALGORITHMS` and `XMLSecEnc::DEFAULT_DATA_ALGORITHMS`, both authenticated/OAEP-only). Unauthenticated CBC modes remain available for interop but are malleable — prefer AES-GCM.
- XPath (`REC-xpath-19991116`) transforms are **rejected during verification by default**. They evaluate a document-supplied XPath expression in `validateReference()` before any signature crypto runs, so a crafted expression is a pre-authentication CPU denial-of-service — and the expression is arbitrary XPath by design, so it cannot be sanitized. SAML and WS-Security do not use them. Set `$objDSig->allowXPathTransforms = true` only if you must verify signatures that legitimately rely on XPath transforms and you trust the source. Signing is unaffected. When enabled, the count/namespace caps below still apply.
- XPath transforms (once enabled) are capped by default (`maxXPathTransforms` / `maxXPathNamespaces`, defaults 5 and 20). Raise or lower these on the `XMLSecurityDSig` instance if your use case needs different limits.
- `add509Cert(..., $isURL = true)` fetches over http/https only and rejects hosts that resolve to loopback/private/link-local/reserved/CGNAT addresses, with redirects disabled (SSRF hardening). `file://` is disabled unless you pass `array('allow_file_scheme' => true)` in `$options`. Only fetch certificates from trusted URLs — a small DNS-rebinding window remains.
- Decrypted XML containing a `DOCTYPE` is rejected to guard against entity-expansion / XXE. Always load untrusted *input* documents yourself with DTD/entity processing disabled.
- Documents carrying a `DOCTYPE` are rejected during signature verification (`locateSignature()` / `verifyDocument()`). This closes the entity-reference bypass in which an `Id="&e;"` attribute is resolved by `getAttribute()` but is invisible to the XPath reference lookup (a libxml2 hashing bug, the same root cause as CVE-2025-23369), causing `verify()` to validate a different node than the one your application reads. Set `$objDSig->forbidDoctype = false` only if you fully trust the document source and require DTD support.
- **Legacy interoperability (temporary):** if you must accept documents/peers that rely on pre-4.0 behaviour, call `$objDSig->enableLegacyMode()` and/or `$objenc->enableLegacyMode()` once after construction. That restores the interoperability settings in one place (DOCTYPE allowed on verify, XPath transforms allowed without count caps, RSA-1.5 key transport allowed). It does **not** undo always-on hardening such as SignatureMethod/key binding, uniform decryption errors, or DOCTYPE rejection in *decrypted* XML. Prefer migrating peers and removing the call.

Breaking changes (3.1 → 4.0)
----------------------------

[](#breaking-changes-31--40)

### Platform

[](#platform)

- **PHP 8.0+ required** (was 5.4+)
- **`phpseclib/phpseclib` ~3.0 required**; `ext-openssl` is now optional

### Signature verification

[](#signature-verification)

- **DOCTYPE rejected by default** during verification (`locateSignature` / `verifyDocument`). Opt out: `$dsig->forbidDoctype = false` or `enableLegacyMode()`
- **XPath Filtering Transforms rejected by default** on verify. Opt in: `$dsig->allowXPathTransforms = true` or `enableLegacyMode()`. Signing unchanged
- **XPath caps** when enabled: max 5 transforms / 20 namespaces per transform (`$maxXPathTransforms` / `$maxXPathNamespaces`; raised by `enableLegacyMode()`)
- **`verify()` always requires SignatureMethod === key algorithm**; mismatch throws (not restored by legacy mode)
- **HMAC keys cannot be loaded from certs/PEM**
- **References fail closed**: unresolved, external, or duplicate-Id URIs throw; same-document only
- **Unknown CanonicalizationMethod rejected**
- **HMAC verify returns `1`/`0`** — always check `=== 1`

### Encryption / decryption

[](#encryption--decryption)

- **RSA-1.5 key transport denied by default**. Opt in: `$enc->allowRSA15KeyTransport = true` or `enableLegacyMode()`
- **Single decrypt error message**: `Failure decrypting Data` (do not branch on exception text)
- **DOCTYPE rejected in decrypted XML** (not restored by legacy mode)
- **EncryptedKey/RetrievalMethod depth capped**
- **ISO 10126 pad length validated** on CBC decrypt

### Certificate URL fetch (`add509Cert`)

[](#certificate-url-fetch-add509cert)

- Only `http`/`https` by default; `file://` needs `['allow_file_scheme' => true]`
- Private/loopback/link-local/reserved/CGNAT targets rejected; redirects disabled

### API signature changes (defaults preserve most callers)

[](#api-signature-changes-defaults-preserve-most-callers)

- `processTransforms(..., $signing = false)`
- `staticLocateKeyInfo(..., $depth = 0, $allowRSA15 = false)`
- `fromEncryptedKeyElement(..., $depth = 0, $allowRSA15 = false)`

### Legacy mode

[](#legacy-mode)

`$dsig->enableLegacyMode()` / `$enc->enableLegacyMode()` restores **DOCTYPE (verify), XPath transforms + uncapped limits, and RSA-1.5** only. It does **not** undo algorithm/key binding, uniform decrypt errors, decrypted-XML DOCTYPE rejection, Reference fail-closed behavior, SSRF rules, or the PHP/phpseclib requirements.

**Migration tip:** Prefer `verifyDocument()` with a pinned key. Use legacy mode only while updating peers.

### Verifying a signature (recommended)

[](#verifying-a-signature-recommended)

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

$doc = new DOMDocument();
$doc->load('./path/to/signed.xml');

// Pin the key/certificate you trust (do NOT read it from the document).
$objKey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA256, array('type' => 'public'));
$objKey->loadKey('./path/to/trusted-cert.pem', true, true);

$objDSig = new XMLSecurityDSig();
// If assertions use custom Id attributes (e.g. WS-Security), declare them first:
// $objDSig->idKeys = array('wsu:Id');
// $objDSig->idNS   = array('wsu' => 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd');

try {
    // Throws on any failure; returns the validated nodes on success.
    $validatedNodes = $objDSig->verifyDocument($objKey, $doc);
    // Operate ONLY on $validatedNodes from here on.
} catch (Exception $e) {
    // Verification failed - reject the message.
}
```

### Decrypting XML (recommended recipe)

[](#decrypting-xml-recommended-recipe)

xmlseclibs does not derive the decryption key from the document: you supply your own private key, and the document's session key is unwrapped with it. The recipe below covers the common `EncryptedKey` (key transport) + `EncryptedData`(data) layout used by SAML and WS-Security, with the algorithm policy pinned.

```
use RobRichards\XMLSecLibs\XMLSecEnc;
use RobRichards\XMLSecLibs\XMLSecurityKey;

$doc = new DOMDocument();
$doc->load('./path/to/encrypted.xml');

$objenc = new XMLSecEnc();

// Pin the algorithm policy (all optional, but recommended):
//  - RSA-1.5 key transport is already denied by default (Bleichenbacher);
//    only set this if you must interoperate with a legacy peer.
// $objenc->allowRSA15KeyTransport = true;
//  - Restrict data encryption to authenticated AES-GCM (rejects CBC):
$objenc->allowedDataAlgorithms = XMLSecEnc::DEFAULT_DATA_ALGORITHMS;
//  - Restrict key transport to RSA-OAEP:
$objenc->allowedKeyAlgorithms  = XMLSecEnc::DEFAULT_KEY_ALGORITHMS;

$encData = $objenc->locateEncryptedData($doc);
if (! $encData) {
    throw new Exception('Cannot locate EncryptedData');
}
$objenc->setNode($encData);
$objenc->type = $encData->getAttribute('Type');

// Resolve the session key. locateKey() reads the data algorithm from the
// document; locateKeyInfo() finds the EncryptedKey.
$objKey = $objenc->locateKey();
if (! $objKey) {
    throw new Exception('Unknown data encryption algorithm');
}

if ($objKeyInfo = $objenc->locateKeyInfo($objKey)) {
    if ($objKeyInfo->isEncrypted) {
        // Load YOUR trusted private key to unwrap the session key.
        $objKeyInfo->loadKey('./path/to/your-private-key.pem', true);
        $sessionKey = $objKeyInfo->encryptedCtx->decryptKey($objKeyInfo);
        $objKey->loadKey($sessionKey);
    }
}

// If the session key was supplied out-of-band (no EncryptedKey), load it here:
// if (empty($objKey->key)) { $objKey->loadKey($sharedSecretBytes); }

// Decrypted content is returned; a DOCTYPE in the plaintext is rejected.
$decrypted = $objenc->decryptNode($objKey, true);
```

If the recipient key is selected by `KeyName` (rather than an embedded `EncryptedKey`), read `$objKeyInfo->name` and load the matching local private key yourself before decrypting. Never treat key material from the document as trusted.

How to Install
--------------

[](#how-to-install)

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

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

Use cases
---------

[](#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
-----------

[](#basic-usage)

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

```
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 = '';
*/
// 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
-----------------

[](#how-to-contribute)

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

Mailing List:

###  Health Score

72

—

ExcellentBetter than 100% of packages

Maintenance85

Actively maintained with recent releases

Popularity74

Solid adoption and visibility

Community50

Growing community involvement

Maturity70

Established project with proven stability

 Bus Factor1

Top contributor holds 69.3% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~145 days

Recently: every ~152 days

Total

29

Last Release

25d ago

Major Versions

1.4.2 → 3.0.02017-05-25

2.0.x-dev → 3.0.22018-09-27

2.1.0 → 3.0.42019-11-05

1.4.3 → 3.0.x-dev2020-04-22

3.1.x-dev → 4.0.0-beta12026-07-24

PHP version history (5 changes)1.4.0PHP &gt;= 5.2

2.0.0PHP &gt;= 5.3

3.0.0PHP &gt;= 5.6

3.0.1PHP &gt;= 5.4

4.0.0-beta1PHP &gt;= 8.0

### Community

Maintainers

![](https://www.gravatar.com/avatar/9af772aa86aa0ec7758c8357bace8270cce545c1ea1e2a2701900f6dc3d24f7c?d=identicon)[robrichards](/maintainers/robrichards)

---

Top Contributors

[![robrichards](https://avatars.githubusercontent.com/u/210629?v=4)](https://github.com/robrichards "robrichards (131 commits)")[![jaimeperez](https://avatars.githubusercontent.com/u/1942728?v=4)](https://github.com/jaimeperez "jaimeperez (11 commits)")[![thijskh](https://avatars.githubusercontent.com/u/3808792?v=4)](https://github.com/thijskh "thijskh (7 commits)")[![Maks3w](https://avatars.githubusercontent.com/u/1301698?v=4)](https://github.com/Maks3w "Maks3w (6 commits)")[![RichWeber](https://avatars.githubusercontent.com/u/1702252?v=4)](https://github.com/RichWeber "RichWeber (4 commits)")[![tmilos](https://avatars.githubusercontent.com/u/1818373?v=4)](https://github.com/tmilos "tmilos (3 commits)")[![gfaust-qb](https://avatars.githubusercontent.com/u/13354975?v=4)](https://github.com/gfaust-qb "gfaust-qb (3 commits)")[![klemenb](https://avatars.githubusercontent.com/u/2099210?v=4)](https://github.com/klemenb "klemenb (3 commits)")[![hiddewie](https://avatars.githubusercontent.com/u/1073881?v=4)](https://github.com/hiddewie "hiddewie (3 commits)")[![tvdijen](https://avatars.githubusercontent.com/u/841045?v=4)](https://github.com/tvdijen "tvdijen (2 commits)")[![restena-sw](https://avatars.githubusercontent.com/u/6346943?v=4)](https://github.com/restena-sw "restena-sw (2 commits)")[![humbe1985](https://avatars.githubusercontent.com/u/22669629?v=4)](https://github.com/humbe1985 "humbe1985 (1 commits)")[![h3xx](https://avatars.githubusercontent.com/u/615684?v=4)](https://github.com/h3xx "h3xx (1 commits)")[![dvaeversted](https://avatars.githubusercontent.com/u/1611810?v=4)](https://github.com/dvaeversted "dvaeversted (1 commits)")[![njake](https://avatars.githubusercontent.com/u/16844901?v=4)](https://github.com/njake "njake (1 commits)")[![AlexanderWillner](https://avatars.githubusercontent.com/u/307605?v=4)](https://github.com/AlexanderWillner "AlexanderWillner (1 commits)")[![DannyvdSluijs](https://avatars.githubusercontent.com/u/618940?v=4)](https://github.com/DannyvdSluijs "DannyvdSluijs (1 commits)")[![chaouchAbderraouf](https://avatars.githubusercontent.com/u/14640773?v=4)](https://github.com/chaouchAbderraouf "chaouchAbderraouf (1 commits)")[![sammarshallou](https://avatars.githubusercontent.com/u/68663?v=4)](https://github.com/sammarshallou "sammarshallou (1 commits)")[![sbacelic](https://avatars.githubusercontent.com/u/647434?v=4)](https://github.com/sbacelic "sbacelic (1 commits)")

---

Tags

xmlsecuritysignaturexmldsig

### Embed Badge

![Health badge](/badges/robrichards-xmlseclibs/health.svg)

```
[![Health](https://phpackages.com/badges/robrichards-xmlseclibs/health.svg)](https://phpackages.com/packages/robrichards-xmlseclibs)
```

###  Alternatives

[greenter/xmldsig

Libreria para firmar XML según normativa de SUNAT en Facturación Electrónica

40878.7k12](/packages/greenter-xmldsig)[ass/xmlsecurity

The XmlSecurity library is written in PHP for working with XML Encryption and Signatures

955.7M36](/packages/ass-xmlsecurity)[fr3d/xmldsig

Tool for easy management of XML Signatures (http://www.w3.org/TR/xmldsig-core/)

64155.7k1](/packages/fr3d-xmldsig)[lyquidity/xml-signer

A PHP to create and verify XAdES signature

2174.7k1](/packages/lyquidity-xml-signer)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
