Mojo-SAML

 view release on metacpan or  search on metacpan

lib/Mojo/XMLSig.pm  view on Meta::CPAN

    unless my $s_method = $elem->at('ds|SignatureMethod[Algorithm]', %ns)->{Algorithm};

  my $siginfo = $elem->at('ds|SignedInfo', %ns);

  # inject namespace if necessary
  if ($siginfo->tag =~ /^([^:]+):/) {
    my $prefix = $1;
    my $ns = $siginfo->namespace;
    $siginfo = _dom($siginfo);
    $siginfo->at(':root')->attr("xmlns:$prefix" => $ns);
  }

  my $canon = _do_action($c_method, $siginfo);
  my $value = _do_action($s_method, $verify, $canon, $elem, $key);

  unless ($verify) {
    Carp::croak 'No SignatureValue present'
      unless my $sig = $dom->at('ds|SignatureValue', %ns);
    $sig->content($value);
  }

  return $dom;
}

sub _verify_rsa {
  my ($algo, $text, $dom, $key) = @_;
  unless ($key) {
    Carp::croak 'No X509Certificate element found for cert storage'
      unless my $elem = $dom->at('ds|KeyInfo > ds|X509Data > ds|X509Certificate:not(:empty)', %ns);
    my $cert = format_cert($elem->text);

    require Crypt::OpenSSL::X509;
    require Crypt::OpenSSL::RSA;
    $cert = Crypt::OpenSSL::X509->new_from_string($cert);
    $key  = Crypt::OpenSSL::RSA->new_public_key($cert->pubkey);
  }

  $key->$set_algo($algo);
  Carp::croak 'No SignatureValue present'
    unless my $sig = $dom->at('ds|SignatureValue:not(:empty)', %ns);
  $sig = Mojo::Util::b64_decode($sig->text);

  Carp::croak 'Signature does not verify'
    unless $key->verify($text, $sig);

  return $sig;
}

1;

=head1 NAME

Mojo::XMLSig - An implementation of XML-Sig using the Mojo toolkit

=head1 SYNOPSIS

  use Mojo::XMLSig;

  # sign
  my $xml = ...;
  my $key = Crypt::OpenSSL::RSA->new_private_key(...);
  my $signed = Mojo::XMLSig::sign($xml, $key);

  # verify using an embedded certificate
  my $verified = Mojo::XMLSig::verify($signed);

  # verify using a known public certificate
  my $pub = Crypt::OpenSSL::RSA->new_public_key(...);
  my $verified = Mojo::XMLSig::verify($signed, $pub);

=head1 DESCRIPTION

L<Mojo::XMLSig> is an implementation of the L<XML Signature Syntax and Processing Version 1.1|https://www.w3.org/TR/xmldsig-core1/> spec.
It allows a user to sign and verify documents in XML format.
This is a requirement for many SAML documents and recommended in nearly all others.

It is important to note that module does not create any tags.
Rather it relies on you passing in a document with the relevant sections included.
It will then fill out the computed sections given the parameters and algorithms specified.
In this way signing and verifying are actually quite similar.

An example document to be signed could be as follows.

  <Thing ID="abc123">
    <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="#abc123">
          <ds:Transforms>
            <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
            <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></ds:DigestValue>
        </ds:Reference>
      </ds:SignedInfo>
      <ds:SignatureValue></ds:SignatureValue>
      <ds:KeyInfo>
        <ds:X509Data>
          <ds:X509Certificate>$cert</ds:X509Certificate>
        </ds:X509Data>
      </ds:KeyInfo>
    </ds:Signature>

    <Important>Cool Stuff</Important>
  </Thing>

where C<$cert> is an x509 certificate, base64 encoded (but typically stripped of all formatting), if embedding the certificate.
Note that the KeyInfo section is not required if not embedding the certificate.

Calling L</sign> on this document will return a new document with the DigestValue and SignatureValue elements populated.
While multiple Reference tags are supported, if multiple Signature tags are provided only the first one will be used.

Note that L<Mojo::SAML::Document::Signature> and other relevant documents can be used to produce the signature for you if need be.

=head1 CAVEATS

This implementation only covers RSA signing and cannot process XPath directives.
Once other algorithms are implemented, the apis will accept more than just RSA keys.
I'm sure there are plenty of other things it can't do too.



( run in 1.956 second using v1.01-cache-2.11-cpan-39bf76dae61 )