Git Product home page Git Product logo

x509ds's Introduction

X509DS - Digital Signature generation Library for XML Requests

Build Status Coverage Status

Introduction

X509DS is a library to help with the tedious process of appending a digital signature node to a X509 authentication request. A X509 request normally looks something like this:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header>
  <wsa:Action xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing/" soapenv:actor="" soapenv:mustUnderstand="0">http://schemas.xmlsoap.org/ws/2005/02/trust/RST/SCT
  </wsa:Action>
  <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" soapenv:actor="" soapenv:mustUnderstand="1">
    <wsu:Timestamp xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="timestamp">
      <wsu:Created>2015-12-16T13:39:36Z</wsu:Created>
      <wsu:Expires>2015-12-16T13:44:36Z</wsu:Expires>
    </wsu:Timestamp>
    <wsse:BinarySecurityToken xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" wsu:Id="binarytoken">MII...</wsse:BinarySecurityToken>
  </wsse:Security>
</soapenv:Header>
<soapenv:Body xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="body">
  <RequestSecurityToken xmlns="http://schemas.xmlsoap.org/ws/2005/02/trust">
    <TokenType>http://schemas.xmlsoap.org/ws/2005/02/sc/sct</TokenType>
    <RequestType>http://schemas.xmlsoap.org/ws/2005/02/trust/Issue</RequestType>
  </RequestSecurityToken>
</soapenv:Body>
</soapenv:Envelope>

Most of the time you want to append a signature into the header, which hashes and canonizes some of the nodes of the XML document. Ultimatelly the whole signature node woll be signed by private key of your x509 certificate. The resulting XML document would look like this:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header>
  <wsa:Action xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing/" soapenv:actor="" soapenv:mustUnderstand="0">http://schemas.xmlsoap.org/ws/2005/02/trust/RST/SCT
  </wsa:Action>
  <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" soapenv:actor="" soapenv:mustUnderstand="1">
    <wsu:Timestamp xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="timestamp">
      <wsu:Created>2015-12-16T13:39:36Z</wsu:Created>
      <wsu:Expires>2015-12-16T13:44:36Z</wsu:Expires>
    </wsu:Timestamp>
    <wsse:BinarySecurityToken xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" wsu:Id="binarytoken"><MII.../wsse:BinarySecurityToken>
  </wsse:Security>
    <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
        <ds:SignedInfo>
            <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
            <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
            <ds:Reference URI="#body">
                <ds:Transforms>
                    <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
                </ds:Transforms>
                <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
                <ds:DigestValue>Emk...</ds:DigestValue>
            </ds:Reference>
            <ds:Reference URI="#timestamp">
                <ds:Transforms>
                    <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
                </ds:Transforms>
                <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
                <ds:DigestValue>2TR...</ds:DigestValue>
            </ds:Reference>
            <ds:Reference URI="#binarytoken">
                <ds:Transforms>
                    <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
                </ds:Transforms>
                <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
                <ds:DigestValue>/Ntf...</ds:DigestValue>
            </ds:Reference>
        </ds:SignedInfo>
        <ds:SignatureValue>tuO...</ds:SignatureValue>
    </ds:Signature>
</soapenv:Header>
<soapenv:Body xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="body">
  <RequestSecurityToken xmlns="http://schemas.xmlsoap.org/ws/2005/02/trust">
    <TokenType>http://schemas.xmlsoap.org/ws/2005/02/sc/sct</TokenType>
    <RequestType>http://schemas.xmlsoap.org/ws/2005/02/trust/Issue</RequestType>
  </RequestSecurityToken>
</soapenv:Body>
</soapenv:Envelope>

The process of creating the signature is rather tedious, because you need to deal with the encryption and openssl on the one hand and with the PHP []DOMDocument](https://secure.php.net/manual/en/dom.setup.php) on the other. This library is there to provide an easy interface for creating digital signatures. The corresponding PHP code for creating a digital signature like in the example before, would look like this:

use X509DS\Signer;

$signer = Signer::fromPrivateKey('path/to/pkey');
$signer->setTags(
    [
        'Body'                 => '#body',
        'Timestamp'            => '#timestamp',
        'BinarySecurityToken'  => '#binarytoken',
    ]
);
$signer->setCanonization(Canonization::C14N_EXCLUSIVE);
$document = $signer->sign(self::XML); //The signed DOMDocument
$document->saveXml(); //The signed XML document as a string

As you can see the whole process doesn't take more than 4 statements. Of course you can configure different things on how the signature is built. More on this topic in the advanced usage part.

Requirements

Installation

Via composer:
composer require snowiow/x509ds

Usage

Create a Signer object:

Either from a private key or pfx.

Private Key

// Either from the path of the private key
$signer = Signer::fromPrivateKey('path/to/pkey');
// or the string content of the private key
$signer = Signer::fromPrivateKey(file_get_contents('path/to/pkey'));
// or an openssl resource
$signer = Signer::fromPrivateKey(openssl_pkey_get_private(file_get_contents('path/to/pkey')));

Pfx File

// Either from the path of the pfx file
$signer = Signer::fromPfx('/path/to/pfx', 'password of pfx');
// or the string content of the pfx file
$signer = Signer::fromPfx(file_get_contents('/path/to/pfx'), 'password of pfx');

Set the canonization method. DEFAULT: C14N

// Can be one of
$signer->setCanonization(Canonization::C14N); //Default
$signer->setCanonization(Canonization::C14N_EXCLUSIVE);
$signer->setCanonization(Canonization::C14N_WITH_COMMENTS);
$signer->setCanonization(Canonization::C14N_WITH_COMMENTS_EXCLUSIVE);

Set the digest method. DEFAULT: SHA1

// Can be one of
$signer->setDigestMethod(Digest::SHA1); //Default
$signer->setDigestMethod(Digest::SHA256);
$signer->setDigestMethod(Digest::SHA512);
$signer->setDigestMethod(Digest::RIPEMD160);

Set the signature method. DEFAULT: SHA1

// Can be one of
$signer->setSignatureMethod(Digest::SHA1); //Default
$signer->setSignatureMethod(Digest::SHA256);
$signer->setSignatureMethod(Digest::SHA512);
$signer->setSignatureMethod(Digest::RIPEMD160);

Set a target. DEFAULT: Header

The signature node can be appended to an arbitrary node as a child.

// Example values (namespace doesn't need to be given)
$signer->setTarget('Header'); //Default
$signer->setTarget('Body');

Set the tags. DEFAULT: []

Set the names of the nodes, of which you need digest values in your signature. The method is called setTags, because the nodes will be searched via the DOMDocument method getElementsByTagName. Additonal methods like getElementsByTagNameNS and getElementById will be added in a later version. The tags are required as an array, where the key is the node name and the value is the uri, which will be set as an attribute in the reference node of the digest value.

// Example
$signer->setTag(
    [
        'Body'                 => '#body',
        'Timestamp'            => '#timestamp',
        'BinarySecurityToken'  => '#binarytoken',
    ]
);

Set a Security Token Reference Node (Optional)

Sometimes an additional SecurityTokenReference node is needed. The node will be added to the signature and looks like this:

<ds:KeyInfo>
    <wsse:SecurityTokenReference>
        <wsse:Reference URI="#binarySecurityToken">
    </wsse:SecurityTokenReference>
</ds:KeyInfo>

The uri can be configured:

// Example
$signer->setSecurityTokenReference('#binarySecurityToken');

Sign a document

Finally you can sign your XML document. This will return the modified DOMDocument with the signature node:

$signedDoc = $signer->sign('path/to/xml'); // from a path
$signedDoc = $signer->sign(file_get_contents('path/to/xml')); // from a content string
// or from a DOMDocument
$document = new DOMDocument();
$document->load('path/to/xml');
$signedDoc = $signer->sign($document);

Get certificate from pfx file

Because a pfx file contains both, the private key and the certificate you can also retrieve the extracted certificate and use it for example to insert it into the BinaraySecurityToken node:

$signer = Signer::fromPfx('/path/to/pfx', 'password of pfx');
$cert = $signer->getCertificate();

x509ds's People

Contributors

snowiow avatar

Stargazers

Randy Schütt avatar

Watchers

James Cloos avatar Randy Schütt avatar  avatar

Forkers

demvsystems

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.