view release on metacpan or search on metacpan
lib/Authen/NZRealMe/ICMSResolutionRequest.pm view on Meta::CPAN
reference_transforms => [ 'ec14n' ],
reference_digest_method => 'sha256',
namespaces => [ @$ns_soap ],
);
my $parser = XML::LibXML->new();
my $doc = $parser->parse_string($xml);
my $xc = XML::LibXML::XPathContext->new($doc->documentElement);
$xc->registerNs( @$_ ) foreach @all_ns;
my $sig_frag = $parser->parse_string($sig_xml)->documentElement();
$sig_frag->{Id} = 'SIG-4'; # Add Id attr for backwards compatibility
# Generate a cert fingerprint and append to the signature block
my $x509 = Crypt::OpenSSL::X509->new_from_string($signer->pub_cert_text);
my $fingerprint = $x509->fingerprint_sha1() =~ s/://gr;
my $fingerprint_sha1 = encode_base64(pack("H*", $fingerprint), '');
my $x = XML::Generator->new();
my $keyinfo_block = $x->KeyInfo( $ns_ds, { Id => "KI-${fingerprint}1" },
$x->SecurityTokenReference( $ns_wsse, { Id => "STR-${fingerprint}2" },
$x->KeyIdentifier( $ns_wsse, { EncodingType => URI('wss_b64'), ValueType => URI('wss_sha1') },
$fingerprint_sha1,
),
),
).'';
my $x509_frag = $parser->parse_string($keyinfo_block)->documentElement();
$sig_frag->appendChild($x509_frag);
# Insert signature block as last element in soap:Header/wsse:Security section
my($sec_node) = $xc->findnodes("/soap:Envelope/soap:Header/wsse:Security");
$sec_node->appendChild($sig_frag);
return $doc->toString(0);
}
1;
__END__
=head1 NAME
lib/Authen/NZRealMe/LogonStrength.pm view on Meta::CPAN
=item Authen::NZRealMe::LogonStrength::STRENGTH_MODERATE_SMS
=back
=head1 METHODS
=head2 new( strength )
Creates an object from the named strength identifier which might be a word
(e.g.: 'low'), a URN (see the RealMe Login service SAML v2.0 Messaging
Specification), or a URN fragment matching the last portion of a URN (e.g.:
'OTP:Token:SID').
=head2 urn( )
Returns the URN for the selected logon strength.
=head2 score( )
Returns the strength score (currently either 10 or 20) which is used when
comparing strengths using the 'minimum' match type.
lib/Authen/NZRealMe/XMLEnc.pm view on Meta::CPAN
sub id_attr { shift->{id_attr}; }
sub decrypt_encrypted_data_elements {
my($self, $xml) = @_;
my $xc = $self->_xcdom_from_xml($xml);
my $frag_parser = XML::LibXML->new();
foreach my $ed_node ($xc->findnodes('//xenc:EncryptedData')) {
my $node_type = $ed_node->{Type} // '<undefined>';
die "Unable to process EncryptedData of type '$node_type'"
unless $node_type eq URI('xenc_type_element');
my $plaintext = $self->_decrypt_one_encrypted_data_element($xc, $ed_node);
my $frag = $frag_parser->parse_balanced_chunk($plaintext);
my $parent = $ed_node->parentNode;
$parent->replaceChild($frag, $ed_node);
}
my($root) = $xc->findnodes('/');
return $root->toString();
}
sub encrypt_one_element {
my($self, $xml, %args) = @_;
lib/Authen/NZRealMe/XMLEnc.pm view on Meta::CPAN
my $target_id = $args{target_id} or croak "Need target_id";
my $algorithm_name = $args{algorithm} or croak "Need algorithm";
my $random_key_algorithm_name = $args{key_algorithm} or croak "Need random key algorithm";
my $id_attr = '@' . $self->id_attr;
my($node) = $xc->findnodes(qq{//*[$id_attr='$target_id']})
or croak "failed to find element with $id_attr='$target_id'";
my $frag_xml = $node->toStringC14N();
my $algorithm = $self->_find_enc_alg($algorithm_name);
my $key_info = $self->_gen_key($algorithm);
my $rsa_alg = $self->_find_enc_alg($random_key_algorithm_name);
my $rsa_key = $self->rsa_public_key();
$key_info->{encrypted_key} =
$self->_encrypt_bytes($rsa_alg, $rsa_key, $key_info->{key});
my $ciphertext = $self->_encrypt_bytes($algorithm, $key_info, $frag_xml);
my $enc_frag = $self->_generate_encrypted_data_element(
$key_info, $ciphertext, $random_key_algorithm_name, $algorithm_name
);
my $frag_parser = XML::LibXML->new();
my $ed_node = $frag_parser->parse_balanced_chunk($enc_frag);
my $parent = $node->parentNode;
$parent->replaceChild($ed_node, $node);
my($root) = $xc->findnodes('/');
return $root->toString();
}
sub _generate_encrypted_data_element {
my($self, $key_info, $ciphertext, $random_key_algorithm_name, $algorithm_name) = @_;
my $encrypted_key_b64 = encode_base64($key_info->{encrypted_key});
my $ciphertext_b64 = encode_base64($key_info->{iv} . $ciphertext);
my $x = XML::Generator->new(':strict', pretty => 2);
my $enc_frag = $x->EncryptedData($ns_xenc,
{ Type => URI('xenc_type_element'), },
$x->EncryptionMethod($ns_xenc,
{ Algorithm => URI($algorithm_name) },
),
$x->KeyInfo($ns_ds,
$x->EncryptedKey($ns_xenc,
$x->EncryptionMethod($ns_xenc,
{ Algorithm => URI($random_key_algorithm_name) },
),
$x->CipherData($ns_xenc,
$x->CipherValue($ns_xenc, "\n" . $encrypted_key_b64),
),
),
),
$x->CipherData($ns_xenc,
$x->CipherValue($ns_xenc, "\n" . $ciphertext_b64),
),
) . '';
return $enc_frag;
}
sub _xcdom_from_xml {
my($self, $xml, @namespaces) = @_;
my $parser = XML::LibXML->new();
my $doc = $parser->parse_string($xml);
my $xc = XML::LibXML::XPathContext->new($doc->documentElement);
lib/Authen/NZRealMe/XMLEnc.pm view on Meta::CPAN
two rounds of encryption are performed. First, an AES key is generated at
random and used by the block cipher to encrypt the assertion. Next, the AES
key is encrypted using the Service Provider's RSA public key and the result is
included along with the encrypted assertion. See the test suite for more
details.
=head2 decrypt_encrypted_data_elements( $xml )
Takes an XML document (as a string) and returns a modified version (also as a
string) in which all C<< <EncryptedData> >> elements are replaced with the
unencrypted document fragment.
=head2 encrypt_one_element
Currently only needed by the test suite, which calls it like this:
my $encrypted_xml = $encrypter->encrypt_one_element($signed_xml,
algorithm => 'xenc_aes128cbc',
target_id => $target_id,
);
lib/Authen/NZRealMe/XMLSig.pm view on Meta::CPAN
return $self;
}
sub id_attr { shift->{id_attr}; }
sub reference_transforms { shift->{reference_transforms}; }
sub reference_digest_method { shift->{reference_digest_method}; }
sub c14n_method { shift->{c14n_method}; }
sub signature_algorithm { shift->{signature_algorithm}; }
sub include_x509_cert { shift->{include_x509_cert}; }
sub _signed_fragment_paths { @{ shift->{signed_fragment_paths} }; }
sub sign {
my($self, $xml, $target_id, %options) = @_;
my $return_signature_xml = delete $options{return_signature_xml};
my $refs = $options{references} // [ { ref_id => $target_id } ];
my $ns_map = delete($options{namespaces}) // [];
my $xc = $self->_xcdom_from_xml($xml, @$ns_map);
my $doc = $xc->getContextNode();
my $sig_xml = $self->_make_sig_xml($xc, %options, references => $refs);
# Just return the XML of the signature block if that's what the caller wants
return $sig_xml if $return_signature_xml;
# Otherwise, add sig fragment to source doc as first child of first ref
my $sig_frag = $self->_xml_to_dom($sig_xml);
my $ref_id_0 = $refs->[0]->{ref_id};
my $target = $self->_find_element_by_uri_reference($xc, $ref_id_0);
if($target->hasChildNodes()) {
$target->insertBefore($sig_frag, $target->firstChild);
}
else {
$target->appendChild($sig_frag);
}
return $doc->toString;
}
sub _xml_to_dom {
my($self, $xml) = @_;
my $parser = XML::LibXML->new();
lib/Authen/NZRealMe/XMLSig.pm view on Meta::CPAN
my @namespaces = @_;
# Verifying an enveloped signature performs destructive operations on the
# DOM, so we need a new DOM for each <Signature> block.
my $sig_count = do {
my $xc = $self->_xcdom_from_xml($xml, @namespaces);
my @sigs = $xc->findnodes($selector);
scalar(@sigs);
};
my @signed_fragment_paths;
eval {
for(my $i = 0; $i < $sig_count; $i++) {
my $xc = $self->_xcdom_from_xml($xml, @namespaces);
my($sig_node) = ($xc->findnodes($selector))[$i];
die "No signature block match for selector: '$selector'"
unless $sig_node;
my $sig_block = $self->_parse_signature_block($xc, $sig_node);
my @frags = $self->_verify_one_signature_block($xc, $sig_block);
push @signed_fragment_paths, @frags;
}
1;
} or do {
my $message = $@ =~ s/\n+\z//r;
croak "Signature verification failed. $message";
};
croak "XML document contains no signatures" unless @signed_fragment_paths;
$self->{signed_fragment_paths} = \@signed_fragment_paths;
return 1;
}
sub _verify_one_signature_block {
my($self, $xc, $sig_block) = @_;
my(@signed_fragment_paths);
# Confirm that the signature is valid for the <SignedInfo> block
my $input = [ $xc, $sig_block->{sig_info_node}];
my $sig_info_plaintext = $self->_apply_transform($sig_block->{c14n}, $input);
$self->_verify_signature(
$sig_block->{signature_algorithm},
$sig_info_plaintext,
$sig_block->{signature_value}
) or die "SignedInfo block signature does not match\n";
# Confirm the digest value for each reference
my $references = $sig_block->{references};
die "Signature block contains no references\n" unless @$references;
foreach my $ref ( @$references ) {
my $fragment = [ $xc, $ref->{xml_node} ];
my $transforms = $ref->{transforms};
foreach my $transform ( @$transforms ) {
$fragment = $self->_apply_transform($transform, $fragment);
}
my $digest = $self->_apply_transform($ref->{digest_method}, $fragment);
if($digest ne $ref->{digest_value}) {
die "Digest of signed element '$ref->{ref_id}' "
. "differs from that given in reference block\n"
. "Expected: '$ref->{digest_value}'\n"
. "Calculated: '$digest'\n ";
}
push @signed_fragment_paths, $ref->{xml_fragment_path};
}
return @signed_fragment_paths;
}
sub _parse_signature_block {
my($self, $xc, $sig) = @_;
my $sig_as_text = $sig->toString;
my $block = {};
my($sig_info) = $xc->findnodes(q{./ds:SignedInfo}, $sig)
lib/Authen/NZRealMe/XMLSig.pm view on Meta::CPAN
my $ref_as_text = $ref_node->toString;
my $ref_data = {};
my $ref_uri = $xc->findvalue('./@URI', $ref_node)
or die "Reference element is missing the URI attribute";
$ref_uri =~ s{^#}{};
$ref_data->{ref_id} = $ref_uri;
my $target_node = $self->_find_element_by_uri_reference($xc, $ref_uri);
$ref_data->{xml_node} = $target_node;
$ref_data->{xml_fragment_path} = $self->_node_to_clarkian_path($target_node);
$ref_data->{transforms} = [
map {
my $trans_node = $_;
my $trans_as_text = $trans_node->toString;
my $algorithm = $trans_node->{Algorithm}
or die "Transform element lacks Algorithm attribute in: '$trans_as_text'";
my $transform = $self->_find_transform($algorithm);
if($xc->findnodes('./*')) {
$transform->{args} = $trans_node->toStringEC14N();
lib/Authen/NZRealMe/XMLSig.pm view on Meta::CPAN
@elem = map { $_->ownerElement() } @attr;
}
return $elem[0];
}
sub _node_to_clarkian_path {
my($self, $node) = @_;
my $node_path = $node->nodePath();
my %frag_ns;
do {
if(my $prefix = $node->prefix) {
$frag_ns{$prefix} = $node->namespaceURI;
}
$node = $node->parentNode();
} while($node);
$node_path =~ s{([\w-]+):}{
my $prefix = $1;
my $uri = $frag_ns{$prefix};
"{$uri}";
}ge;
return $node_path;
}
sub _make_sig_xml {
my($self, $xc, %opt) = @_;
my $sig = {};
lib/Authen/NZRealMe/XMLSig.pm view on Meta::CPAN
$self->_transform_as_xml($x, 'CanonicalizationMethod', $ns_ds, $c14n),
$x->SignatureMethod($ns_ds, { Algorithm => $sig_alg->{uri} }),
@ref_blocks,
),
$x->SignatureValue($ns_ds),
@key_info,
) . '';
my $xc = $self->_xcdom_from_xml($sig_xml, @$ns_ds);
my $doc = $xc->getContextNode();
my($fragment) = [ $xc, $xc->findnodes('/ds:Signature/ds:SignedInfo') ];
my $plaintext = $self->_apply_transform($sig->{c14n}, $fragment);
my $sig_text = "\n" . $self->_create_signature(
$sig->{signature_algorithm},
$plaintext,
);
my($sig_node) = $xc->findnodes('//dsig:SignatureValue')
or die "Failed to find SignatureValue in generated signature XML";
$sig_node->addChild( $doc->ownerDocument->createTextNode($sig_text) );
# Serialising, parsing and reserialising simplifies ns attr and empty tags
return $self->_xml_to_dom( $doc->toStringEC14N() )->toString();
lib/Authen/NZRealMe/XMLSig.pm view on Meta::CPAN
if((ref($spec) || '') ne 'HASH') {
die "references must be specified as hashrefs";
}
my $ref = {};
my $ref_uri = $ref->{ref_id} = $spec->{ref_id}
// die "need a 'ref_id' to create a reference";
my $target_node = $self->_find_element_by_uri_reference($xc, $ref_uri);
$ref->{xml_node} = $target_node;
my $fragment = [$xc, $target_node];
my @transforms = map {
$self->_find_transform($_)
} @{ $spec->{transforms} // $self->reference_transforms() };
if(my $ns_list = $spec->{namespaces}) {
if($transforms[-1]->{uri} ne URI('ec14n')) {
$transforms[-1] = $self->_find_transform('ec14n');
}
$transforms[-1]->{namespaces} = $ns_list;
}
$ref->{transforms} = \@transforms;
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;
lib/Authen/NZRealMe/XMLSig.pm view on Meta::CPAN
my $text = <$fh>;
return $text;
}
##############################################################################
# Methods for applying transforms
#
# A transform method takes a parameter '$input' which must either be a DOM
# fragment or a string. Some of the transform methods also accept a second
# parameter '$args' which is a hashref defining the parameters of the transform
# in more detail.
#
# In the case of a DOM fragment, we also need the XPathContext object to
# facilitate the use of namespaces in queries. Therefore the input parameter
# will be a reference to an array of two elements: the context object, followed
# by the DOM fragment node:
#
# [ $xc, $node ]
#
# String input will be a simple scalar. The _input_as_context_dom() helper
# method can be used to turn a string into a DOM fragment/context pair.
#
# The return value from the transform method will either be a DOM fragment
# /context pair or a string - depending on the type of transform.
#
# The process for calling these methods is:
#
# 1. Use $self->_find_transform($name_or_uri) to get a $transform hashref
# describing the transform.
# 2. Optionally plug some extra parameters into the $transform hashref.
# 3. Call $self->_apply_transform($transform, $input)
#
lib/Authen/NZRealMe/XMLSig.pm view on Meta::CPAN
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( )
t/35-xml-sig-units.t view on Meta::CPAN
my($verifier, $signer, $xml, $xc, $node, $input, $output, $error);
##############################################################################
# Transform methods
$verifier = $sig_class->new(
pub_cert_text => slurp_file($idp_cert_file),
);
my($tr_by_name, $tr_by_uri, $expected, $parser, $doc, $frag);
ok('1', '===== C14N Canonicalisation =====');
$tr_by_name = $verifier->_find_transform('c14n');
$tr_by_uri = $verifier->_find_transform('http://www.w3.org/TR/2001/REC-xml-c14n-20010315');
is(ref($tr_by_name) => 'HASH', 'found c14n by name');
is(ref($tr_by_uri) => 'HASH', 'found c14n by URI');
is($tr_by_name->{uri} => $tr_by_uri->{uri}, 'same transform URI');
is($tr_by_name->{method} => $tr_by_uri->{method}, 'same transform method name');
t/35-xml-sig-units.t view on Meta::CPAN
$expected = q{<Doc xmlns="https://example.com/doc/" aaa="one" bbb="two" ccc="three">
<Title>Example Document</Title>
</Doc>};
$output = $verifier->_apply_transform($tr_by_name, $input);
is($output, $expected, 'canonical output (from string)');
$xc = parse_xml_to_xc($input);
$output = $verifier->_apply_transform($tr_by_name, [$xc, $xc->getContextNode]);
is($output, $expected, 'canonical output (from DOM fragment)');
ok('1', '===== C14N-With-Comments Canonicalisation =====');
$tr_by_name = $verifier->_find_transform('c14n_wc');
$tr_by_uri = $verifier->_find_transform('http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments');
is(ref($tr_by_name) => 'HASH', 'found c14n_wc by name');
is(ref($tr_by_uri) => 'HASH', 'found c14n_wc by URI');
is($tr_by_name->{uri} => $tr_by_uri->{uri}, 'same transform URI');
is($tr_by_name->{method} => $tr_by_uri->{method}, 'same transform method name');
t/35-xml-sig-units.t view on Meta::CPAN
$expected = q{<Doc xmlns="https://example.com/doc/" aaa="one" bbb="two" ccc="three">
<Title>Example Document</Title><!-- a comment -->
</Doc>};
$output = $verifier->_apply_transform($tr_by_name, $input);
is($output, $expected, 'canonical output (from string)');
$xc = parse_xml_to_xc($input);
$output = $verifier->_apply_transform($tr_by_name, [$xc, $xc->getContextNode]);
is($output, $expected, 'canonical output (from DOM fragment)');
ok('1', '===== C14N Fragment Canonicalisation =====');
$tr_by_name = $verifier->_find_transform('c14n');
$input = q{<box:Container xmlns:box="https://example.com/box/"><Doc ccc="three"
bbb="two"
aaa="one"
xmlns="https://example.com/doc/">
<Title>Example Document</Title><!-- a comment -->
</Doc></box:Container>};
$expected = q{<Doc xmlns="https://example.com/doc/" xmlns:box="https://example.com/box/" aaa="one" bbb="two" ccc="three">
<Title>Example Document</Title>
</Doc>};
$xc = parse_xml_to_xc($input, 'doc' => 'https://example.com/doc/');
($frag) = $xc->findnodes('//doc:Doc');
isa_ok($frag => 'XML::LibXML::Element', 'fragment node');
$output = $verifier->_apply_transform($tr_by_name, [$xc, $frag]);
is($output, $expected, 'canonical output (from DOM fragment)');
ok('1', '===== C14N11 Canonicalisation =====');
$tr_by_name = $verifier->_find_transform('c14n11');
$tr_by_uri = $verifier->_find_transform('http://www.w3.org/2006/12/xml-c14n11');
is(ref($tr_by_name) => 'HASH', 'found c14n11 by name');
is(ref($tr_by_uri) => 'HASH', 'found c14n11 by URI');
is($tr_by_name->{uri} => $tr_by_uri->{uri}, 'same transform URI');
is($tr_by_name->{method} => $tr_by_uri->{method}, 'same transform method name');
t/35-xml-sig-units.t view on Meta::CPAN
$expected = q{<Doc xmlns="https://example.com/doc/" aaa="one" bbb="two" ccc="three">
<Title>Example Document</Title>
</Doc>};
$output = $verifier->_apply_transform($tr_by_name, $input);
is($output, $expected, 'canonical output (from string)');
$xc = parse_xml_to_xc($input);
$output = $verifier->_apply_transform($tr_by_name, [$xc, $xc->getContextNode]);
is($output, $expected, 'canonical output (from DOM fragment)');
ok('1', '===== C14N11-With-Comments Canonicalisation =====');
$tr_by_name = $verifier->_find_transform('c14n11_wc');
$tr_by_uri = $verifier->_find_transform('http://www.w3.org/2006/12/xml-c14n11#WithComments');
is(ref($tr_by_name) => 'HASH', 'found c14n11_wc by name');
is(ref($tr_by_uri) => 'HASH', 'found c14n11_wc by URI');
is($tr_by_name->{uri} => $tr_by_uri->{uri}, 'same transform URI');
is($tr_by_name->{method} => $tr_by_uri->{method}, 'same transform method name');
t/35-xml-sig-units.t view on Meta::CPAN
$expected = q{<Doc xmlns="https://example.com/doc/" aaa="one" bbb="two" ccc="three">
<Title>Example Document</Title><!-- a comment -->
</Doc>};
$output = $verifier->_apply_transform($tr_by_name, $input);
is($output, $expected, 'canonical output (from string)');
$xc = parse_xml_to_xc($input);
$output = $verifier->_apply_transform($tr_by_name, [$xc, $xc->getContextNode]);
is($output, $expected, 'canonical output (from DOM fragment)');
ok('1', '===== C14N11 Fragment Canonicalisation =====');
$tr_by_name = $verifier->_find_transform('c14n11');
$input = q{<box:Container xmlns:box="https://example.com/box/"><Doc ccc="three"
bbb="two"
aaa="one"
xmlns="https://example.com/doc/">
<Title>Example Document</Title><!-- a comment -->
</Doc></box:Container>};
$expected = q{<Doc xmlns="https://example.com/doc/" xmlns:box="https://example.com/box/" aaa="one" bbb="two" ccc="three">
<Title>Example Document</Title>
</Doc>};
$xc = parse_xml_to_xc($input, 'doc' => 'https://example.com/doc/');
($frag) = $xc->findnodes('//doc:Doc');
isa_ok($frag => 'XML::LibXML::Element', 'fragment node');
$output = $verifier->_apply_transform($tr_by_name, [$xc, $frag]);
is($output, $expected, 'canonical output (from DOM fragment)');
ok('1', '===== EC14N Canonicalisation =====');
$tr_by_name = $verifier->_find_transform('ec14n');
$tr_by_uri = $verifier->_find_transform('http://www.w3.org/2001/10/xml-exc-c14n#');
is(ref($tr_by_name) => 'HASH', 'found ec14n by name');
is(ref($tr_by_uri) => 'HASH', 'found ec14n by URI');
is($tr_by_name->{uri} => $tr_by_uri->{uri}, 'same transform URI');
is($tr_by_name->{method} => $tr_by_uri->{method}, 'same transform method name');
t/35-xml-sig-units.t view on Meta::CPAN
$expected = q{<Doc xmlns="https://example.com/doc/" aaa="one" bbb="two" ccc="three">
<Title>Example Document</Title>
</Doc>};
$output = $verifier->_apply_transform($tr_by_name, $input);
is($output, $expected, 'canonical output (from string)');
$xc = parse_xml_to_xc($input);
$output = $verifier->_apply_transform($tr_by_name, [$xc, $xc->getContextNode]);
is($output, $expected, 'canonical output (from DOM fragment)');
ok('1', '===== EC14N-With-Comments Canonicalisation =====');
$tr_by_name = $verifier->_find_transform('ec14n_wc');
$tr_by_uri = $verifier->_find_transform('http://www.w3.org/2001/10/xml-exc-c14n#WithComments');
is(ref($tr_by_name) => 'HASH', 'found ec14n_wc by name');
is(ref($tr_by_uri) => 'HASH', 'found ec14n_wc by URI');
is($tr_by_name->{uri} => $tr_by_uri->{uri}, 'same transform URI');
is($tr_by_name->{method} => $tr_by_uri->{method}, 'same transform method name');
t/35-xml-sig-units.t view on Meta::CPAN
$expected = q{<Doc xmlns="https://example.com/doc/" aaa="one" bbb="two" ccc="three">
<Title>Example Document</Title><!-- a comment -->
</Doc>};
$output = $verifier->_apply_transform($tr_by_name, $input);
is($output, $expected, 'canonical output (from string)');
$xc = parse_xml_to_xc($input);
$output = $verifier->_apply_transform($tr_by_name, [$xc, $xc->getContextNode]);
is($output, $expected, 'canonical output (from DOM fragment)');
ok('1', '===== EC14N Fragment Canonicalisation =====');
$tr_by_name = $verifier->_find_transform('ec14n');
$input = q{<box:Container xmlns:box="https://example.com/box/"><Doc ccc="three"
bbb="two"
aaa="one"
xmlns="https://example.com/doc/">
<Title>Example Document</Title><!-- a comment -->
</Doc></box:Container>};
$expected = q{<Doc xmlns="https://example.com/doc/" aaa="one" bbb="two" ccc="three">
<Title>Example Document</Title>
</Doc>};
$xc = parse_xml_to_xc($input, 'doc' => 'https://example.com/doc/');
($frag) = $xc->findnodes('//doc:Doc');
isa_ok($frag => 'XML::LibXML::Element', 'fragment node');
$output = $verifier->_apply_transform($tr_by_name, [$xc, $frag]);
is($output, $expected, 'canonical output (from DOM fragment)');
ok('1', '===== Enveloped Signature =====');
$tr_by_name = $verifier->_find_transform('env_sig');
$tr_by_uri = $verifier->_find_transform('http://www.w3.org/2000/09/xmldsig#enveloped-signature');
is(ref($tr_by_name) => 'HASH', 'found env-sig by name');
is(ref($tr_by_uri) => 'HASH', 'found env-sig by URI');
is($tr_by_name->{uri} => $tr_by_uri->{uri}, 'same transform URI');
is($tr_by_name->{method} => $tr_by_uri->{method}, 'same transform method name');
t/35-xml-sig-units.t view on Meta::CPAN
</dsig:SignedInfo>
</dsig:Signature>
<Title>Example Document</Title><!-- a comment -->
</Doc>};
$expected = q{<Doc>
<Title>Example Document</Title><!-- a comment -->
</Doc>};
$output = $verifier->_apply_transform($tr_by_name, $input);
isa_ok($output => 'ARRAY', 'fragment node');
$output = $output->[1];
isa_ok($output => 'XML::LibXML::Element', 'transformed document node');
is($output->toStringEC14N(1), $expected, 'env-sig output (from string)');
$xc = parse_xml_to_xc($input, @ns_ds);
$output = $verifier->_apply_transform($tr_by_name, [$xc, $xc->getContextNode]);
isa_ok($output => 'ARRAY', 'fragment node');
$output = $output->[1];
isa_ok($output => 'XML::LibXML::Element', 'transformed document node');
is($output->toStringEC14N(1), $expected, 'env-sig output (from DOM fragment)');
ok('1', '===== SHA1 Digest =====');
$input = q{<Doc>
<Title>Example Document</Title><!-- a comment -->
</Doc>};
$tr_by_name = $verifier->_find_transform('sha1');
$tr_by_uri = $verifier->_find_transform('http://www.w3.org/2000/09/xmldsig#sha1');
is(ref($tr_by_name) => 'HASH', 'found sha1 by name');
is(ref($tr_by_uri) => 'HASH', 'found sha1 by URI');
is($tr_by_name->{uri} => $tr_by_uri->{uri}, 'same transform URI');
is($tr_by_name->{method} => $tr_by_uri->{method}, 'same transform method name');
$output = $verifier->_apply_transform($tr_by_name, $input);
is($output, 'zCGTIejOvqGvd6KSmlk4aFOW4Ro=', 'sha1 digest output (from string)');
# No test for sha1 digest with a DOM fragment as input - since any sane
# implementation would use a c14n transform to provide an input string.
ok('1', '===== SHA256 Digest =====');
$input = q{<Doc>
<Title>Example Document</Title><!-- a comment -->
</Doc>};
$tr_by_name = $verifier->_find_transform('sha256');
$tr_by_uri = $verifier->_find_transform('http://www.w3.org/2001/04/xmlenc#sha256');
t/35-xml-sig-units.t view on Meta::CPAN
is(ref($tr_by_name) => 'HASH', 'found sha256 by name');
is(ref($tr_by_uri) => 'HASH', 'found sha256 by URI');
is($tr_by_name->{uri} => $tr_by_uri->{uri}, 'same transform URI');
is($tr_by_name->{method} => $tr_by_uri->{method}, 'same transform method name');
$output = $verifier->_apply_transform($tr_by_name, $input);
is($output, 'WjnmbezTqKqqU7dyvyFO46FwLTa3KBOsklKGLYK4Ge4=',
'sha256 digest output (from string)'
);
# No test for sha256 digest with a DOM fragment as input - since any sane
# implementation would use a c14n transform to provide an input string.
##############################################################################
# Raw signature methods
my $plaintext = 'This is some plain text';
my $mismatched_text = 'This is some different plain text';
$signer = $sig_class->new(
key_text => slurp_file($idp_key_file),
t/35-xml-sig-units.t view on Meta::CPAN
ok('1', '===== verify() method =====');
$verifier = $sig_class->new(
pub_cert_text => slurp_file($idp_cert_file),
);
eval { $verifier->verify($xml); };
is($@, '', 'signature verification was successful');
my @frags = $verifier->_signed_fragment_paths;
is(scalar(@frags), 1, 'one signed fragment was found');
is($frags[0], '/Container/Assertion', 'XPath for signed fragment');
$xc = parse_xml_to_xc($xml);
$node = eval {
$verifier->find_verified_element($xc, '/Assertion');
};
like($@, qr{No element matches: '/Assertion'}, 'XPath did not match');
$node = eval {
$verifier->find_verified_element($xc, '/Container/Unsafe/Assertion');
};
like($@,
qr{Element matching '/Container/Unsafe/Assertion' is not in a signed fragment},
'XPath matched unsigned element'
);
$node = eval { $verifier->find_verified_element($xc, '/Container/Assertion'); };
is($@, '', 'found a verified element');
isa_ok($node => 'XML::LibXML::Element', 'fragment node');
is($node->{ID} => 'Idd02c7c2232759874e1c205587017bed', 'got the assertion node');
my $name = $xc->findvalue('./Identity/Name', $node);
is($name => 'Bob', 'fragment includes <Name> element');
##############################################################################
# Try again but with referenced content that does not match the signature
# i.e.: tamper with the signed content.
$verifier = $sig_class->new(
pub_cert_text => slurp_file($idp_cert_file),
);
t/36-xml-sig-multi.t view on Meta::CPAN
ok($ref, 'successfully parsed signature block');
is(
scalar(@{ $ref->{references} }),
1,
'SigInfo block contains one reference'
);
done_testing(); exit;
my @frags = eval {
$verifier->_verify_one_signature_block($xc, $ref);
};
is($@, '', 'verification did not throw exception');
eval {
$verifier->verify($xml);
};
like(
$@,
qr{SignedInfo block signature does not match},
t/39-icms-req.t view on Meta::CPAN
my $parser = XML::LibXML->new();
my $doc = $parser->parse_string($icms_req);
my $xc = XML::LibXML::XPathContext->new($doc->documentElement);
$xc->registerNs( @$_ ) foreach @all_ns;
my($node) = eval {
$verifier->find_verified_element($xc, '//soap12:Header');
};
ok(!$node, "failed to find SOAP Header element");
like($@, qr{not in a signed fragment}, ' because it is outside signed areas');
($node) = eval {
$verifier->find_verified_element($xc, '//soap12:Header/wsa:Action');
};
is($@, '', 'wsa:Action inside SOAP Header is verified');
is(
$node->to_literal,
'http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Validate',
' and has expected content'
);