Skip to content
This repository has been archived by the owner on Jan 25, 2024. It is now read-only.
/ message-signer Public archive

A flexible message signing and verification framework. Includes Guzzle Plugin.

Notifications You must be signed in to change notification settings

fortrabbit/message-signer

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

13 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Build Status

Update

This project is abandoned. This repository is still here for documentation purpose.

Message Signer

A flexible message signing and verification framework.

So what do you do with it? For example: Write a HTTP REST API server. Sign your client requests with a private key. Verify the request with a public key on your API server.

Installing via Composer

php composer.phar require "frbit/message-signer:*"

Features

Signature transport formats

There are three essential information required to verify the validity of a message:

  • Key: To identify the client (the one sending the signed message) and to select the correct key to verify the signature.
  • Date: It's not really necessary. It allows the server (the one receiving and validating the message) to accept only "recent" messages - otherwise attackers could at least re-send intercepted messages easily.
  • Signature: Well, to proof the validity of the message.

Those signature information can be transported in various formats. There are three formats built-in and additional/custom formats can be easily added.

The formats are implemented in the \Frbit\MessageSigner\Message\Handler\* classes.

Multiple header

Default format.

Here, each information is stored in a dedicated message header (eg HTTP request header).

X-Sign: The-signature-content
X-Sign-Key: The-key-name
X-Sign-Date: The-date

Of course, the names of the headers are arbitrary - as long as client and server know both about them.

$builder = new \Frbit\MessageSigner\Builder();
$builder->setMessageHandler(new \Frbit\MessageSigner\Message\Handler\DefaultHeaderHandler());
$signer = $builder->build();

Single Header

In this format, all information are stored (embedded) in a single, URL encoded header.

X-Sign: sign=The-signature-content&key=The-key-name&date=The-date

Again: the name of the header is arbitrary...

$builder = new \Frbit\MessageSigner\Builder();
$builder->setMessageHandler(new \Frbit\MessageSigner\Message\Handler\EmbeddedHeaderHandler());
$signer = $builder->build();

Parameter

In some scenarios it makes sense to store the information in message parameters (eg HTTP request query string).

/foo?sign=The-signature-content&key=The-key-name&date=The-date

As before: parameter names (sign, date, key) are arbitrary.

$builder = new \Frbit\MessageSigner\Builder();
$builder->setMessageHandler(new \Frbit\MessageSigner\Message\Handler\ParameterHandler());
$signer = $builder->build();

Examples

Have a look in the examples/ folder for additional code examples.

Send a signed request with guzzle

<?php

require __DIR__ . '/../vendor/autoload.php';

// key repo is required
$keys = new \Frbit\MessageSigner\KeyRepository\ArrayKeyRepository(array(
    'default' => array(
        file_get_contents(__DIR__ . '/keys/key1.pem'),
        file_get_contents(__DIR__ . '/keys/key1.pub')
    ),
));

// build up signer
$builder = new \Frbit\MessageSigner\Builder();
$signer  = $builder->setKeys($keys)->build();

// generate guzzle3 and add plugin (see examples for guzzle4)
$client = new \Guzzle\Http\Client('http://localhost:1234');
$plugin = new \Frbit\MessageSigner\Guzzle\Plugin($signer);
$client->addSubscriber($plugin);

// perform the (signed) request
$client->post('/foo', array('X-Foo' => 'Bar', 'X-Sign-Key' => 'default'), 'body-content')->send();

This would send a request like:

POST /foo HTTP/1.1
Host: localhost:12345
User-Agent: Guzzle/3.8.1 curl/7.22.0 PHP/5.4.25
X-Sign-Key: default
X-Sign-Date: 2014-03-05T18:55:30+01:00
X-Sign: AemEhtuO47X+XJK+3GHKsWXxjt9cuUuOa1OSQCrXuPtToMEvV0tmPC1dPzhYiz/zw3DlOGy69p34MvKFJRyImWoKxkVD7JVHNf5Vq4N1PsZv/JFsyaKgy8uc9WRLZWgRLxNDR8DPQ8IMU7560HHx2WhpFSrFazpiU23MHF5s+QA=
Content-Length: 12

body-content

Sign a Symfony HttpFoundation request

<?php

require __DIR__ . '/../vendor/autoload.php';

// build up signer params
$keys           = new \Frbit\MessageSigner\KeyRepository\ArrayKeyRepository(array(
    'default' => array(
        file_get_contents(__DIR__ . '/keys/key1.pem'),
        file_get_contents(__DIR__ . '/keys/key1.pub')
    )
));
$crypto         = new \Frbit\MessageSigner\Crypto\OpenSslCrypto();
$encoder        = new \Frbit\MessageSigner\Encoder\Base64Encoder();
$serializer     = new \Frbit\MessageSigner\Serializer\JsonSerializer();
$messageHandler = new \Frbit\MessageSigner\Message\Handler\DefaultHeaderHandler();

// create signer
$signer = new \Frbit\MessageSigner\Signer\RequestSigner($messageHandler, $encoder, $serializer, $crypto, $keys);

// generate symfony request
$request = \Symfony\Component\HttpFoundation\Request::create(
    'http://localhost:1234/foo', 'POST', array(), array(), array(), array(), 'the-content'
);

// sign request
$message   = new \Frbit\MessageSigner\Message\SymfonyRequestMessage($request);
$signature = $signer->sign('default', $message);

// dump request
echo "-------------\n$request\n-------------\n\n";

Would print

-------------
POST /foo HTTP/1.1
Accept:          text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Charset:  ISO-8859-1,utf-8;q=0.7,*;q=0.7
Accept-Language: en-us,en;q=0.5
Content-Type:    application/x-www-form-urlencoded
Host:            localhost:1234
User-Agent:      Symfony/2.X
X-Sign:          Vq/5na+sP8EQB6m5S7K/JdS9QaAD1U9lyIPdpIT4+CdboPRVI4OT/nNlt1ipjfGelwaaNd48em21F/zVr8il9IxZMQxzP4a9//Z8xQR1Ecf88Abk94MsAfwok7t6PwyBMqckSbzAUa8QjRQm0d/4su2WQ/4yekCcxRMrYKdguro=
X-Sign-Date:     2014-03-05T18:51:38+01:00
X-Sign-Key:      default

the-content
-------------

About

A flexible message signing and verification framework. Includes Guzzle Plugin.

Resources

Stars

Watchers

Forks

Packages

No packages published

Languages