Class webcoder31\ezxmldsig\XMLDSigToken

Build or analyze an XML token.

An XML token is an enveloping XML Digital Signature (cf. RFC 3275) containing signed and timestamped user data. These data may also be encrypted. In this case we talk about Secure XML token.

This class uses the following default algorithms to operate:

The analysis expects these algorithms unless its options name others (see __construct()), and it requires a trust anchor: the CA certificates and/or the pinned certificate the signing certificate is verified against. Without it, no token is valid.

An XML token looks like this:

<?xml version="1.0"?>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
  <ds:SignedInfo>
    <ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
    <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
    <ds:Reference URI="#Token">
      <ds:Transforms>
        <ds:Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
      </ds:Transforms>
      <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
      <ds:DigestValue>---- TOKEN HASH ----</ds:DigestValue>
    </ds:Reference>
  </ds:SignedInfo>
  <ds:SignatureValue>---- SIGNATURE VALUE ----</ds:SignatureValue>
  <ds:KeyInfo>
    <ds:X509Data>
      <ds:X509Certificate>---- X.509 CERTIFICATE ----</ds:X509Certificate>
    </ds:X509Data>
  </ds:KeyInfo>
  <ds:Object Id="Token">
    <Token>
      <TokenTimestamp>2026-10-17T04:43:05Z</TokenTimestamp>
      <TokenId>---- 128-BIT RANDOM IDENTIFIER (HEXADECIMAL) ----</TokenId>
      <TokenData>
        <data1 Algorithm="base64">---- BASE64 ENCODED DATA ----</data1>
        <data2 Algorithm="base64">---- BASE64 ENCODED DATA ----</data2>
        <data3>
          <data31 Algorithm="base64">---- BASE64 ENCODED DATA ----</data31>
          <data32 Algorithm="base64">---- BASE64 ENCODED DATA ----</data32>
        </data3>
        <data4 Algorithm="base64">---- BASE64 ENCODED DATA ----</data4>
      </TokenData>
    </Token>
  </ds:Object>
</ds:Signature>

The signing process consists of the following actions:

  • Load data from an associative array.

  • Encode data values using Base64.

  • Build a node from the encoded array of data (cf. node <TokenData />).

  • Compute an UTC timestamp and store it in a node <TokenTimestamp />.

  • Generate a random identifier of 128 bits (random_bytes()) and store it, in hexadecimal, in a node <TokenId />. Signed with the rest of the token, it lets the receiver refuse a token it has already accepted (see getTokenId()).

  • Aggregate the nodes <TokenTimestamp />, <TokenId /> and <TokenData /> inside a node <Token />.

  • Load the base DOM document representing an XML digital signature:

<ds:Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
  <ds:SignedInfo>
    <ds:SignatureMethod />
  </ds:SignedInfo>
</ds:Signature>
  • Create a node <ds:Object Id="Token" /> and append it to the node <ds:Signature />.

  • Add the node <Token /> to the node <ds:Object Id="Token" />.

  • NOTE: If data encryption is requested, this process will take place here (this will be described later).

  • Build a node <ds:Reference URI="#Token" /> and append it to the node <ds:SignedInfo />. This consists of:

    • Canonicalizing the content of the node <ds:Object Id="Token" />.

    • Computing the hash (SHA-256 by default) of the canonicalized node and storing it in the node <ds:DigestValue />.

  • Include, in the XML token, the X.509 certificate associated to the private key that will be used to perform the signing (see the next steps below). This certificate will be used to perform the signature validation process, avoiding the need, for the receiver of the XML Digital Signature, to own it on its side.

  • Canonicalize the content of the node <ds:SignedInfo />.

  • Compute the signature of the canonicalized node using the private key dedicated to perform signing.

  • Store the result in the node <ds:SignatureValue />.

  • Save the DOM document in XML format.

The signature validation process consists of the following actions:

  • Load the XML Digital Signature in a DOM document. A document with a document type declaration (DOCTYPE), or not encoded in UTF-8, is refused before it is parsed, and the parser never accesses the network (see _loadXML()).

  • Verify that the algorithms of the XML Digital Signature are the expected ones.

  • Compute the hash of the content of the node <ds:Object Id="Token" /> with the digest algorithm.

  • Compare the computed hash with the one stored in the node <ds:DigestValue />. If the hashes are different, this means that the content of the node <ds:Object Id="Token" /> has been altered.

  • Canonicalize the content of the node <ds:SignedInfo />.

  • Compute the signature of the node <ds:SignedInfo /> using the X.509 certificate included in the XML token.

  • Compare the computed signature with the one stored in the node <ds:SignatureValue>. If the signatures are different, this means that the content of the node <ds:SignedInfo /> has not been signed using the private key associated to the X.509 certificate included in the XML Digital Signature.

  • Verify that the X.509 certificate included in the XML Digital Signature is trusted, against the trust anchor given to the analysis: CA certificates up to which OpenSSL verifies the chain of the certificate, and/or the pinned certificate the token must be signed with. Without a trust anchor, no token is valid: anyone can sign a token with a certificate of their own.

  • NOTE: If data decryption is required, this process will take place here (this will be described later).

  • Extract the timestamp and the identifier stored in the content of the node <ds:Object Id="Token" /> and memorise them. A token without identifier is rejected.

  • Extract the data stored in the content of the node <ds:Object Id="Token" />.

  • Decode data values using Base64.

  • Build an associative array containing the decoded data.

Token data encryption / decryption:

The token data may also be encrypted before signing. In this case the class will use the following default algorithms to perform encryption and decryption of data:

A secure (encrypted) XML token looks like this:

<?xml version="1.0"?>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
  <ds:SignedInfo>
    <ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
    <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
    <ds:Reference URI="#Token">
      <ds:Transforms>
        <ds:Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
      </ds:Transforms>
      <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
      <ds:DigestValue>---- TOKEN HASH ----</ds:DigestValue>
    </ds:Reference>
  </ds:SignedInfo>
  <ds:SignatureValue>---- SIGNATURE VALUE ----</ds:SignatureValue>
  <ds:KeyInfo>
    <ds:X509Data>
      <ds:X509Certificate>---- X.509 CERTIFICATE ----</ds:X509Certificate>
    </ds:X509Data>
  </ds:KeyInfo>
  <ds:Object Id="Token">
    <xenc:EncryptedData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" Type="http://www.w3.org/2001/04/xmlenc#Content">
      <xenc:EncryptionMethod Algorithm="http://www.w3.org/2009/xmlenc11#aes256-gcm"/>
      <ds:KeyInfo xmlns:dsig="http://www.w3.org/2000/09/xmldsig#">
        <xenc:EncryptedKey>
          <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p"/>
          <xenc:CipherData>
            <xenc:CipherValue>---- CIPHERED SESSION KEY ----</xenc:CipherValue>
          </xenc:CipherData>
        </xenc:EncryptedKey>
      </ds:KeyInfo>
      <xenc:CipherData>
        <xenc:CipherValue>---- ENCRYPTED DATA ----</xenc:CipherValue>
      </xenc:CipherData>
    </xenc:EncryptedData>
  </ds:Object>
</ds:Signature>

The encryption process is the following:

  • Randomly generate a session key.

  • Cipher the session key using the X.509 certificate dedicated to the encryption process, in order to transmit it safely in the XML Digital Signature.

  • Store the ciphered session key in the node <xenc:CipherValue /> which is located inside the node <xenc:EncryptedKey />.

  • Encrypt the content of the node <ds:Object Id="Token" /> using the non-ciphered session key and store the result in the last node <xenc:CipherValue />.

The decryption process is the following:

  • Retrieve the node <xenc:EncryptedData />.

  • Decipher the ciphered session key stored in the node <xenc:CipherValue /> (the one which is located inside the node <xenc:EncryptedKey />) using the private key associated to the X.509 certificate that has been used to perform the encryption.

  • Decrypt the content of the last node <xenc:CipherValue /> using the deciphered session key.

The decryption only takes place once the digest, the signature, the trust in the signing certificate and the algorithms have been verified, and every failure that depends on the encrypted content gives the same error, Token decryption failed!. RSA 1.5 is refused, and a CBC algorithm is only accepted when the analysis declares it (see __construct()).

Replay:

A valid token can be submitted again for as long as isOutOfDate() accepts it. The class keeps no list of the tokens it has analyzed: the caller must keep the identifiers it accepted (getTokenId()) and refuse a token whose identifier is among them.

Located at XMLDSigToken.php
Methods
Constants