Piotr Osipa
Piotr Osipa

Reputation: 65

How to sign SAML 2.0 AuthnRequest with ECDSA (​NIST Curve P-256/​ SHA-256) in PHP

I need to sign SAML 2.0 AuthnRequest with ECDSA (​NIST Curve P-256/​ SHA-256) in PHP.

To create SAML 2.0 AuthnRequest I'm using https://github.com/simplesamlphp/simplesamlphp

I have a private key

Private-Key: (256 bit)
priv:
    0d:.....
pub:
    04:....
ASN1 OID: prime256v1
NIST CURVE: P-256

To create signature, I'm using https://github.com/phpecc/phpecc because https://github.com/robrichards/xmlseclibs does not seem to support NIST Curve P-256/​ SHA-256

I've implemented this example exactly how it is https://github.com/phpecc/phpecc/blob/HEAD/examples/creating_signature.php but I'm getting error from request reciver.

Where do I get from or how can I create <ds:DigestValue>...</ds:DigestValue>

What am I doing this wrong? Am I using wrong libraries? Is there one vendor to support this case?

Upvotes: 2

Views: 1065

Answers (1)

Timothy Legge
Timothy Legge

Reputation: 559

Not the specific tools that you are using but it might help if you still don't have an answer or others are trying to use ecdsa and saml

Perl's XML::Sig module:

install with: sudo cpan XML::Sig

The test t/015_ecdsa_signing.t, of which I will include a modified version, to print the XML two different ways, does what you want.

As you can see it tests the first version of the signature against xmlsec1's implementation. The second version may be a less supported version. XML::Sec can also verify either version.

I don't remember if I have tested Perl's Net::SAML2 with ecdsa but it uses the same version of XML::Sig and would work fine (possibly with tweaks needed).

Note this example signs '<foo ID="123"></foo>' but you simply pass the AuthnRequest and it will sign any tag that includes an ID=somevalue

use strict;
use warnings;

use Test::More tests => 8;
use XML::Sig;
use File::Which;

my $sig = XML::Sig->new( { digest_hash => 'sha256', sig_hash => 'sha256', key => 't/ecdsa.private.pem', cert => 't/ecdsa.public.pem' } );
isa_ok( $sig, 'XML::Sig' );

my $signed = $sig->sign('<foo ID="123"></foo>');
ok($signed, "XML Signed Sucessfully using ecdsa key");

$sig = XML::Sig->new( );
my $is_valid = $sig->verify( $signed );
ok( $is_valid == 1, "XML::Sig signed Validated using X509Certificate");

ok( (open XML, '>', 't/tmp.xml'), "File opened for write");
print XML $signed;
close XML;

SKIP: {
    skip "xmlsec1 not installed", 1 unless which('xmlsec1');

    my $verify_response = `xmlsec1 --verify --trusted-pem t/ecdsa.public.pem --id-attr:ID "foo" t/tmp.xml 2>&1`;
    ok( $verify_response =~ m/^OK/, "ECDSA Response is verified using xmlsec1" )
        or warn "calling xmlsec1 failed: '$verify_response'\n";
    if ($verify_response =~ m/^OK/) {
        unlink 't/tmp.xml';
    } else{
        print $signed;
        die;
    }
}
print "\n==================================\n", $signed, "\n==================================\n";
$sig = XML::Sig->new( { digest_hash => 'sha256', sig_hash => 'sha256', key => 't/ecdsa.private.pem' } );
isa_ok( $sig, 'XML::Sig' );

$signed = $sig->sign('<foo ID="123"></foo>');
ok($signed, "XML Signed Sucessfully using ecdsa key");

print "\n==================================\n", $signed, "\n==================================\n";

$sig = XML::Sig->new( );
$is_valid = $sig->verify( $signed );
ok( $is_valid == 1, "XML::Sig signed Validated using ECDSAKey");

done_testing;

Upvotes: 0

Related Questions