Authen-NZRealMe
view release on metacpan or search on metacpan
lib/Authen/NZRealMe/XMLSig.pm view on Meta::CPAN
foreach my $transform ( @transforms ) {
$fragment = $self->_apply_transform($transform, $fragment);
}
my $digest_method = $ref->{digest_method} = $self->_find_transform(
$spec->{digest_method} // $self->reference_digest_method()
);
$ref->{digest_value} = $self->_apply_transform($digest_method, $fragment);
return $ref;
}
sub find_verified_element {
my($self, $xc, $xpath) = @_;
my($node) = $xc->findnodes($xpath);
croak "No element matches: '$xpath'" unless $node;
# Check if the matching node, or one of its ancestors is in one of
# the signed fragments which were verified earlier.
my @vfrags = $self->_find_signed_fragment_nodes($xc);
my $n = $node;
do {
foreach my $v (@vfrags) {
return $node if $v->isEqual($n);
}
$n = $n->parentNode;
} while ($n);
croak "Element matching '$xpath' is not in a signed fragment";
return $node;
}
sub _find_signed_fragment_nodes {
my($self, $xc) = @_;
my @paths = $self->_signed_fragment_paths;
my %prefix;
my $i = 1;
foreach my $uri ("@paths" =~ m/{(.*?)}/g) {
my $prefix = $prefix{$uri} //= sprintf('_XSig-%02u', $i++);
s/{$uri}/$prefix:/g foreach @paths;
}
while(my($uri, $pfx) = each %prefix) {
$xc->registerNs($pfx => $uri);
}
my @nodes = map { $xc->findnodes($_) } @paths;
return @nodes;
}
sub ignore_bad_signatures { # Called if skip_signature_check is enabled
shift->{signed_fragment_paths} = [ '/' ];
}
sub create_detached_signature {
my($self, $plaintext, $eol) = @_;
$eol //= "\n";
my $algorithm = $self->_find_sig_alg($self->signature_algorithm);
my $b64_sig = $self->_create_signature($algorithm, $plaintext);
$b64_sig =~ s/\s+/$eol/g;
return $b64_sig;
}
sub verify_detached_signature {
my($self, $plaintext, $b64_sig) = @_;
my $algorithm = $self->_find_sig_alg($self->signature_algorithm);
return $self->_verify_signature($algorithm, $plaintext, $b64_sig);
}
sub key_text {
my($self) = @_;
return $self->{key_text} if $self->{key_text};
my $path = $self->{key_file}
or croak "signing key must be set with 'key_file' or 'key_text'";
$self->{key_text} = $self->_slurp_file($path);
return $self->{key_text};
}
sub pub_key_text {
my($self) = @_;
return $self->{pub_key_text} if $self->{pub_key_text};
my $cert_text = $self->pub_cert_text();
my $x509 = Crypt::OpenSSL::X509->new_from_string($cert_text);
$self->{pub_key_text} = $x509->pubkey();
return $self->{pub_key_text};
}
sub pub_cert_text {
my($self) = @_;
return $self->{pub_cert_text} if $self->{pub_cert_text};
my $path = $self->{pub_cert_file}
or croak "signing cert must be set with 'pub_cert_file' or 'pub_cert_text'";
$self->{pub_cert_text} = $self->_slurp_file($path);
return $self->{pub_cert_text};
}
sub _slurp_file {
my($self, $path) = @_;
local($/) = undef;
open my $fh, '<', $path or die "open($path): $!";
my $text = <$fh>;
return $text;
lib/Authen/NZRealMe/XMLSig.pm view on Meta::CPAN
Other recognised options are:
=over 4
=item C<c14n_method>
The canonicalisation method to use when creating a signature block. Default
is 'ec14n'.
=item C<include_x509_cert>
A boolean flag indicating whether the generated signature should include an
X509 representation of the certificate with public key required to verify the
signature.
=item C<signature_algorithm>
The signature algorithm to use when creating a signature block. Default
is 'rsa_sha1'.
=item C<reference_digest_method>
The digest method to use when creating a reference element in a signature
block. Default is 'sha1'.
=item C<reference_transforms>
The list of transforms to usewhen creating a reference element in a signature
block. Must be specified as an arrayref. Default is [ 'env_sig', 'ec14n' ].
=back
=head2 id_attr( )
Returns the name of the attribute used to identify the element being signed.
By default the attribute name is not used at all and the element references are
resolved by matching the URI to any attribute value. Can be set by passing
an C<id_attr> option to the constructor.
=head2 sign( $xml, $target_id, options ... )
Takes an XML document and an optional element ID value and returns a string of
XML with a digital signature added. The XML document can be provided either as
a string or as an XML::LibXML DOM object.
Named options can be provided to customise the transforms and algorithms used
when generating the signature block. In particular, the C<references> option
can be used to supply a list of multiple references. In which case, a value
of C<undef> should be provided for the C<$target_id> parameter:
my $refs = [
{ ref_uri => $first_uri_value },
{ ref_uri => $second_uri_value },
];
$signer->sign($xml, undef, references => $ref);
Each reference can include a list of namespace prefixes to be included in the
canonicalisation transform.
=head2 create_detached_signature( $plaintext, $eol )
Takes a plaintext string, calculates a signature using the private key (and
optionally the signarture algorithm) passed to the constructor and returns a
base64-encoded string. The C<$eol> parameter can be used to specify the
line-ending character used in the base64 encoding process (default: \n).
=head2 verify_detached_signature( $plaintext, $base64_sig )
Takes a plaintext string, and a base64-encoded signature. Verifies the
signature using the public key or certificate supplied to the constructor.
Returns true if the signature is valid, and false otherwise.
=head2 verify( $xml, $selector_xpath, @namespaces )
Takes an XML string (or DOM object); searches for signature elements; verifies
the provided signature and message digest for each; and returns true on success.
The caller would then typically use C<find_verified_element()> to ensure that
subsequent queries target element which were covered by a verified signature.
The C<$selector_xpath> can be used to identify which C<< <Signature> >> element
should be checked. This is particularly useful with documents containing
multiple signatures where each was creaated using a different key (since the
API only provides for a single cert/public key). If not provided, a default
selector of C<'//ds:Signature'> will be used.
If provided, the value for C<$selector_xpath> may use 'ds' as a namespace
prefix for digital signature elements. If any other namespaces are required,
the following arguments are assumed to be C<< prefix => uri >> pairs. For
example this code might be used to verify signatures in the SOAP envelope while
ignoring signatures in the payload withing the SOAP body:
my $selector = '//ds:Signature[not(ancestor::soap12:Body)]';
$verifier->verify($xml, $selector, NS_PAIR('soap12'));
If the provided document does not contain any signatures which match the
selector, or if an invalid signature is found, an exception will be thrown.
=head2 find_verified_element( $xc, $xpath )
This method is a wrapper around the standard L<XML::LibXML> C<findnodes()>
method, which also confirms that the matching node is within one of the signed
fragments which were identified by the earlier call to the C<verify()> method.
The caller must provide an L<XML::LibXML::XPathContext> object with registered
URIs for all namespace prefixes required by the supplied XPath expression.
=head2 ignore_bad_signatures( )
Calling this method after C<verify()> will tag the root element as a verified
fragment. This is used in cases where signature verification failed (perhaps
because the other party has just replaced their signing key) but you wish to
proceed with calling C<find_verified_element()> anyway.
=head2 key_text( )
Returns the private key text which will be used to initialise the
L<Crypt::OpenSSL::RSA> object used for generating signatures.
=head2 pub_key_text( )
Returns the public key text used to initialise the L<Crypt::OpenSSL::RSA>
object used for verifing signatures.
=head2 pub_cert_text( )
( run in 0.531 second using v1.01-cache-2.11-cpan-5a3173703d6 )