Skip to content

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
...
Checking mergeability… Don’t worry, you can still create the pull request.
  • 11 commits
  • 10 files changed
  • 0 commit comments
  • 1 contributor
Commits on Oct 04, 2010
Chris Andrews Fix Canonical XML transformations.
When transforming the XML document during verification, the method calls
implementing canonicalization were misspelled, so attempts to verify
documents specifying the canonicalization transforms would fail.
0429672
Chris Andrews Fix verification of signatures with X509 certificates.
The contents of the <X509Certificate> element were being treated as
a PEM public key, rather than as a PEM certificate. This change uses
Crypt::OpenSSL::X509 to convert the certificate to a public key, which
permits use of this module to verify such documents.
c87c98b
Chris Andrews Handle signed documents with namespaces.
This adds support for documents with namespaces such as SAML assertions.
This module was stripping the namespace prefixes from the document as
part of canonicalization, which means that verification would always
fail.
467812d
Chris Andrews Add a SAML assertion verification test.
This test shows that the module can be used to verify the signature
on a SAML assertion using an X509 certificate.
47411db
Chris Andrews Embed a X509 certificate when signing documents.
The module was embedding a PEM-formatted public key as the value of
the <X509Certificate> element, rather than the certificate. The
public key was derived from the private key, so this change adds a
new "cert" option to allow the corresponding certificate to be provided.

This change permits the TODO in t/006_signing.t to be removed as the
test now passes in its entirety.
e1d0265
Chris Andrews Expose the signer's certificate after a successful verify.
When a document with an embedded X509 certificate has been
successfully verified, the certificate will be available for
verification. The certificate is returned as a Crypt::OpenSSL::X509
object.
bb69c86
Chris Andrews Add a test showing we can roundtrip a SAML request
This shows that we can successfully sign and then verify a SAML
request using an X509 certificate.
6312278
Chris Andrews Apply exclusive canonicalization correctly.
The transform requested, http://www.w3.org/2001/10/xml-exc-c14n#,
requests exclusive canonicalization - make sure that's what we apply.
f4d855a
Chris Andrews Use namespace prefixes throughout.
We now use namespace prefixes when signing, on the elements we add
to the document.
7e6b9e9
Chris Andrews Add the canonicalization transform we do when signing.
We canonicalize before signing, so we need to add that transform
to the set in our SignedInfo. This causes the verify operation to
also canonicalize.

Update the signing test to show that even if the document to be
signed is not already in canonical form we can successfully round-
trip it.
ab1a51a
Commits on Oct 07, 2010
Chris Andrews Add support for X509 verify using an external certificate.
This allows verifying signed documents where the certificate
value is not included.
d957081
Showing with 393 additions and 72 deletions.
  1. +201 −65 lib/XML/Sig.pm
  2. +2 −2 t/005_rsakeys.t
  3. +2 −5 t/006_signing.t
  4. +25 −0 t/007_verify_saml.t
  5. +27 −0 t/008_sign_saml.t
  6. +40 −0 t/009_verify_separate_cert.t
  7. +25 −0 t/logout_response.xml
  8. +10 −0 t/saml_request.xml
  9. +45 −0 t/saml_response.xml
  10. +16 −0 t/sso.cert.pem
View
266 lib/XML/Sig.pm
@@ -36,7 +36,7 @@ sub new {
my $class = shift;
my $params = shift;
my $self = {};
- foreach my $prop ( qw/ key / ) {
+ foreach my $prop ( qw/ key cert cert_text / ) {
if ( exists $params->{ $prop } ) {
$self->{ $prop } = $params->{ $prop };
}
@@ -51,6 +51,12 @@ sub new {
if ( exists $params->{ 'key' } ) {
$self->_load_key( $params->{ 'key' } );
}
+ if ( exists $params->{ 'cert' } ) {
+ $self->_load_cert_file( $params->{ 'cert' } );
+ }
+ if ( exists $params->{ 'cert_text' } ) {
+ $self->_load_cert_text( $params->{ 'cert_text' } );
+ }
return $self;
}
@@ -102,30 +108,56 @@ sub sign {
sub verify {
my $self = shift;
- my ($xml) = @_;
+ delete $self->{signer_cert};
+ my ($xml) = @_;
+
$self->{ parser } = XML::XPath->new( xml => $xml );
+ $self->{ parser }->set_namespace('dsig', 'http://www.w3.org/2000/09/xmldsig#');
- my $signature = _trim($self->{parser}->findvalue('//Signature/SignatureValue'));
- my $signed_info = $self->_get_node_as_text('//Signature/SignedInfo');
- my $signed_info_canon = $self->_canonicalize_xml( $signed_info );
+ my $signature = _trim($self->{parser}->findvalue('//dsig:Signature/dsig:SignatureValue'));
+ my $signed_info_node = $self->_get_node('//dsig:Signature/dsig:SignedInfo');
- my $keyinfo_node;
- if ($keyinfo_node = $self->{parser}->find('//Signature/KeyInfo/X509Data')) {
- return 0 unless $self->_verify_x509($keyinfo_node,$signed_info_canon,$signature);
- }
- elsif ($keyinfo_node = $self->{parser}->find('//Signature/KeyInfo/KeyValue/RSAKeyValue')) {
- return 0 unless $self->_verify_rsa($keyinfo_node,$signed_info_canon,$signature);
+ my $signature_node = $self->_get_node('//dsig:Signature');
+ my $ns;
+ if (defined $signature_node && ref $signature_node) {
+ $ns = $signature_node->getNamespaces->[0];
+ $self->{dsig_prefix} = ($ns->getPrefix eq '#default') ? '' : $ns->getPrefix;
}
- elsif ($keyinfo_node = $self->{parser}->find('//Signature/KeyInfo/KeyValue/DSAKeyValue')) {
- return 0 unless $self->_verify_dsa($keyinfo_node,$signed_info_canon,$signature);
+ else {
+ die "no Signature node?";
+ }
+
+ if (scalar @{ $signed_info_node->getNamespaces } == 0) {
+ $signed_info_node->appendNamespace($ns);
+ }
+
+ my $signed_info = XML::XPath::XMLParser::as_string($signed_info_node);
+ my $signed_info_canon = $self->_canonicalize_xml( $signed_info );
+
+ if (defined $self->{cert_obj}) {
+ # use the provided cert to verify
+ return 0 unless $self->_verify_x509_cert($self->{cert_obj},$signed_info_canon,$signature);
}
else {
- die "Unrecognized key type in signature.";
+ # extract the certficate or key from the document
+ my $keyinfo_node;
+ if ($keyinfo_node = $self->{parser}->find('//dsig:Signature/dsig:KeyInfo/dsig:X509Data')) {
+ return 0 unless $self->_verify_x509($keyinfo_node,$signed_info_canon,$signature);
+ }
+ elsif ($keyinfo_node = $self->{parser}->find('//dsig:Signature/dsig:KeyInfo/dsig:KeyValue/dsig:RSAKeyValue')) {
+ return 0 unless $self->_verify_rsa($keyinfo_node,$signed_info_canon,$signature);
+ }
+ elsif ($keyinfo_node = $self->{parser}->find('//dsig:Signature/dsig:KeyInfo/dsig:KeyValue/dsig:DSAKeyValue')) {
+ return 0 unless $self->_verify_dsa($keyinfo_node,$signed_info_canon,$signature);
+ }
+ else {
+ die "Unrecognized key type or no KeyInfo in document";
+ }
}
- my $digest_method = $self->{parser}->findvalue('//Signature/SignedInfo/Reference/DigestMethod/@Algorithm');
- my $digest = _trim($self->{parser}->findvalue('//Signature/SignedInfo/Reference/DigestValue'));
+ my $digest_method = $self->{parser}->findvalue('//dsig:Signature/dsig:SignedInfo/dsig:Reference/dsig:DigestMethod/@Algorithm');
+ my $digest = _trim($self->{parser}->findvalue('//dsig:Signature/dsig:SignedInfo/dsig:Reference/dsig:DigestValue'));
my $signed_xml = $self->_get_signed_xml();
my $canonical = $self->_transform( $signed_xml );
@@ -135,6 +167,11 @@ sub verify {
return 0;
}
+sub signer_cert {
+ my $self = shift;
+ return $self->{signer_cert};
+}
+
sub _get_xml_to_sign {
my $self = shift;
my $id = $self->{parser}->findvalue('//@ID');
@@ -146,7 +183,7 @@ sub _get_xml_to_sign {
sub _get_signed_xml {
my $self = shift;
- my $id = $self->{parser}->findvalue('//Signature/SignedInfo/Reference/@URI');
+ my $id = $self->{parser}->findvalue('//dsig:Signature/dsig:SignedInfo/dsig:Reference/@URI');
$id =~ s/^#//;
$self->{'sign_id'} = $id;
my $xpath = "//*[\@ID='$id']";
@@ -156,11 +193,11 @@ sub _get_signed_xml {
sub _transform {
my $self = shift;
my ($xml) = @_;
- foreach my $node ($self->{parser}->find('//Transform/@Algorithm')->get_nodelist) {
+ foreach my $node ($self->{parser}->find('//dsig:Transform/@Algorithm')->get_nodelist) {
my $alg = $node->getNodeValue;
if ($alg eq TRANSFORM_ENV_SIG) { $xml = $self->_transform_env_sig($xml); }
- elsif ($alg eq TRANSFORM_EXC_C14N) { $xml = $self->_canonicalize($xml,0); }
- elsif ($alg eq TRANSFORM_EXC_C14N_COMMENTS) { $xml = $self->canonicalize($xml,1); }
+ elsif ($alg eq TRANSFORM_EXC_C14N) { $xml = $self->_canonicalize_xml($xml,0); }
+ elsif ($alg eq TRANSFORM_EXC_C14N_COMMENTS) { $xml = $self->_canonicalize_xml($xml,1); }
else { die "Unsupported transform: $alg"; }
}
return $xml;
@@ -171,9 +208,9 @@ sub _verify_rsa {
my ($context,$canonical,$sig) = @_;
# Generate Public Key from XML
- my $mod = _trim($self->{parser}->findvalue('//Signature/KeyInfo/KeyValue/RSAKeyValue/Modulus'));
+ my $mod = _trim($self->{parser}->findvalue('//dsig:Signature/dsig:KeyInfo/dsig:KeyValue/dsig:RSAKeyValue/dsig:Modulus'));
my $modBin = decode_base64( $mod );
- my $exp = _trim($self->{parser}->findvalue('//Signature/KeyInfo/KeyValue/RSAKeyValue/Exponent'));
+ my $exp = _trim($self->{parser}->findvalue('//dsig:Signature/dsig:KeyInfo/dsig:KeyValue/dsig:RSAKeyValue/dsig:Exponent'));
my $expBin = decode_base64( $exp );
my $n = Crypt::OpenSSL::Bignum->new_from_bin($modBin);
my $e = Crypt::OpenSSL::Bignum->new_from_bin($expBin);
@@ -188,11 +225,7 @@ sub _verify_rsa {
sub _clean_x509 {
my $self = shift;
my ($cert) = @_;
- $cert =~ s/\n//g;
-# my $n = 64; # $n is group size.
-# my @parts = unpack "a$n" x ((length($cert)/$n)-0) . "a*", $cert;
-# $cert = join("\n",@parts);
- $cert = "-----BEGIN PUBLIC KEY-----\n" . $cert . "\n-----END PUBLIC KEY-----\n";
+ $cert = "-----BEGIN CERTIFICATE-----\n" . $cert . "\n-----END CERTIFICATE-----\n";
return $cert;
}
@@ -201,21 +234,38 @@ sub _verify_x509 {
my ($context,$canonical,$sig) = @_;
eval {
- require Crypt::OpenSSL::X509;
- require Crypt::OpenSSL::RSA;
+ require Crypt::OpenSSL::X509;
};
+ confess "Crypt::OpenSSL::X509 needs to be installed so that we can handle X509 certificates" if $@;
# Generate Public Key from XML
- my $certificate = _trim($self->{parser}->findvalue('//Signature/KeyInfo/X509Data/X509Certificate'));
+ my $certificate = _trim($self->{parser}->findvalue('//dsig:Signature/dsig:KeyInfo/dsig:X509Data/dsig:X509Certificate'));
+
# This is added because the X509 parser requires it for self-identification
$certificate = $self->_clean_x509($certificate);
+
+ my $cert = Crypt::OpenSSL::X509->new_from_string($certificate);
+ return $self->_verify_x509_cert($cert, $canonical, $sig);
+}
+
+sub _verify_x509_cert {
+ my $self = shift;
+ my ($cert, $canonical, $sig) = @_;
- my $rsa_pub = Crypt::OpenSSL::RSA->new_public_key($certificate);
+ eval {
+ require Crypt::OpenSSL::RSA;
+ };
+ my $rsa_pub = Crypt::OpenSSL::RSA->new_public_key($cert->pubkey);
# Decode signature and verify
my $bin_signature = decode_base64($sig);
- return 1 if ($rsa_pub->verify( $canonical, $bin_signature ));
+ # If successful verify, store the signer's cert for validation
+ if ($rsa_pub->verify( $canonical, $bin_signature )) {
+ $self->{signer_cert} = $cert;
+ return 1;
+ }
+
return 0;
}
@@ -229,10 +279,10 @@ sub _verify_dsa {
};
# Generate Public Key from XML
- my $p = decode_base64(_trim($self->{parser}->findvalue('//Signature/KeyInfo/KeyValue/DSAKeyValue/P')));
- my $q = decode_base64(_trim($self->{parser}->findvalue('//Signature/KeyInfo/KeyValue/DSAKeyValue/Q')));
- my $g = decode_base64(_trim($self->{parser}->findvalue('//Signature/KeyInfo/KeyValue/DSAKeyValue/G')));
- my $y = decode_base64(_trim($self->{parser}->findvalue('//Signature/KeyInfo/KeyValue/DSAKeyValue/Y')));
+ my $p = decode_base64(_trim($self->{parser}->findvalue('//dsig:Signature/dsig:KeyInfo/dsig:KeyValue/dsig:DSAKeyValue/dsig:P')));
+ my $q = decode_base64(_trim($self->{parser}->findvalue('//dsig:Signature/dsig:KeyInfo/dsig:KeyValue/dsig:DSAKeyValue/dsig:Q')));
+ my $g = decode_base64(_trim($self->{parser}->findvalue('//dsig:Signature/dsig:KeyInfo/dsig:KeyValue/dsig:DSAKeyValue/dsig:G')));
+ my $y = decode_base64(_trim($self->{parser}->findvalue('//dsig:Signature/dsig:KeyInfo/dsig:KeyValue/dsig:DSAKeyValue/dsig:Y')));
my $dsa_pub = Crypt::OpenSSL::DSA->new();
$dsa_pub->set_p($p);
$dsa_pub->set_q($q);
@@ -263,7 +313,11 @@ sub _get_node_as_text {
sub _transform_env_sig {
my $self = shift;
my ($str) = @_;
- $str =~ s/(<Signature(.*?)>(.*?)\<\/Signature>)//igs;
+ my $prefix = '';
+ if (defined $self->{dsig_prefix} && length $self->{dsig_prefix}) {
+ $prefix = $self->{dsig_prefix} . ':';
+ }
+ $str =~ s/(<${prefix}Signature(.*?)>(.*?)\<\/${prefix}Signature>)//igs;
return $str;
}
@@ -293,7 +347,16 @@ sub _load_dsa_key {
my $q = encode_base64( $dsa_key->get_q(), '' );
my $y = encode_base64( $dsa_key->get_pub_key(), '' );
- $self->{KeyInfo} = "<KeyInfo><KeyValue><DSAKeyValue><P>$p</P><Q>$q</Q><G>$g</G><Y>$y</Y></DSAKeyValue></KeyValue></KeyInfo>";
+ $self->{KeyInfo} = "<dsig:KeyInfo>
+ <dsig:KeyValue>
+ <dsig:DSAKeyValue>
+ <dsig:P>$p</dsig:P>
+ <dsig:Q>$q</dsig:Q>
+ <dsig:G>$g</dsig:G>
+ <dsig:Y>$y</dsig:Y>
+ </dsig:DSAKeyValue>
+ </dsig:KeyValue>
+ </dsig:KeyInfo>";
$self->{key_type} = 'dsa';
}
else {
@@ -317,11 +380,7 @@ sub _load_rsa_key {
$self->{ key_obj } = $rsaKey;
$self->{ key_type } = 'rsa';
- if ($self->{'x509'}) {
- my $cert = $rsaKey->get_public_key_x509_string();
- $cert =~ s/-----[^-]*-----//gm;
- $self->{KeyInfo} = "<KeyInfo><X509Data><X509Certificate>\n"._trim($cert)."\n</X509Certificate></X509Data></KeyInfo>";
- } else {
+ if (!$self->{ x509 }) {
my $bigNum = ( $rsaKey->get_key_parameters() )[1];
my $bin = $bigNum->to_bin();
my $exp = encode_base64( $bin, '' );
@@ -329,7 +388,14 @@ sub _load_rsa_key {
$bigNum = ( $rsaKey->get_key_parameters() )[0];
$bin = $bigNum->to_bin();
my $mod = encode_base64( $bin, '' );
- $self->{KeyInfo} = "<KeyInfo><KeyValue><RSAKeyValue><Modulus>$mod</Modulus><Exponent>$exp</Exponent></RSAKeyValue></KeyValue></KeyInfo>";
+ $self->{KeyInfo} = "<dsig:KeyInfo>
+ <dsig:KeyValue>
+ <dsig:RSAKeyValue>
+ <dsig:Modulus>$mod</dsig:Modulus>
+ <dsig:Exponent>$exp</dsig:Exponent>
+ </dsig:RSAKeyValue>
+ </dsig:KeyValue>
+ </dsig:KeyInfo>";
}
}
else {
@@ -350,9 +416,6 @@ sub _load_x509_key {
if ( $x509Key ) {
$x509Key->use_pkcs1_padding();
$self->{ key_obj } = $x509Key;
- my $cert = $x509Key->pubkey;
- $cert =~ s/^-----[^-]*-----\n$//gm;
- $self->{KeyInfo} = "<KeyInfo><X509Data><X509Certificate>\n$cert\n</X509Certificate></X509Data></KeyInfo>";
$self->{key_type} = 'x509';
}
else {
@@ -365,6 +428,64 @@ sub _set_key_info {
}
+sub _load_cert_file {
+ my $self = shift;
+
+ eval {
+ require Crypt::OpenSSL::X509;
+ };
+
+ confess "Crypt::OpenSSL::X509 needs to be installed so that we can handle X509 certs." if $@;
+
+ my $file = $self->{ cert };
+ if ( open my $CERT, '<', $file ) {
+ my $text = '';
+ local $/ = undef;
+ $text = <$CERT>;
+ close $CERT;
+
+ my $cert = Crypt::OpenSSL::X509->new_from_string($text);
+ if ( $cert ) {
+ $self->{ cert_obj } = $cert;
+ my $cert_text = $cert->as_string;
+ $cert_text =~ s/-----[^-]*-----//gm;
+ $self->{KeyInfo} = "<dsig:KeyInfo><dsig:X509Data><dsig:X509Certificate>\n"._trim($cert_text)."\n</dsig:X509Certificate></dsig:X509Data></dsig:KeyInfo>";
+ }
+ else {
+ confess "Could not load certificate from $file";
+ }
+ }
+ else {
+ confess "Could not find certificate file $file";
+ }
+
+ return;
+}
+
+sub _load_cert_text {
+ my $self = shift;
+
+ eval {
+ require Crypt::OpenSSL::X509;
+ };
+
+ confess "Crypt::OpenSSL::X509 needs to be installed so that we can handle X509 certs." if $@;
+
+ my $text = $self->{ cert_text };
+ my $cert = Crypt::OpenSSL::X509->new_from_string($text);
+ if ( $cert ) {
+ $self->{ cert_obj } = $cert;
+ my $cert_text = $cert->as_string;
+ $cert_text =~ s/-----[^-]*-----//gm;
+ $self->{KeyInfo} = "<dsig:KeyInfo><dsig:X509Data><dsig:X509Certificate>\n"._trim($cert_text)."\n</dsig:X509Certificate></dsig:X509Data></dsig:KeyInfo>";
+ }
+ else {
+ confess "Could not load certificate from given text.";
+ }
+
+ return;
+}
+
sub _load_key {
my $self = shift;
my $file = $self->{ key };
@@ -405,35 +526,36 @@ sub _load_key {
sub _signature_xml {
my $self = shift;
my ($signed_info,$signature_value) = @_;
- return qq{<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
+ return qq{<dsig:Signature xmlns:dsig="http://www.w3.org/2000/09/xmldsig#">
$signed_info
- <SignatureValue>$signature_value</SignatureValue>
+ <dsig:SignatureValue>$signature_value</dsig:SignatureValue>
$self->{KeyInfo}
- </Signature>};
+ </dsig:Signature>};
}
sub _signedinfo_xml {
my $self = shift;
my ($digest_xml) = @_;
- return qq{<SignedInfo xmlns="http://www.w3.org/2000/09/xmldsig#" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">
- <CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments" />
- <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#$self->{key_type}-sha1" />
+ return qq{<dsig:SignedInfo xmlns:dsig="http://www.w3.org/2000/09/xmldsig#" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">
+ <dsig:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments" />
+ <dsig:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#$self->{key_type}-sha1" />
$digest_xml
- </SignedInfo>};
+ </dsig:SignedInfo>};
}
sub _reference_xml {
my $self = shift;
my ($digest) = @_;
my $id = $self->{sign_id};
- return qq{<Reference URI="#$id">
- <Transforms>
- <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
- </Transforms>
- <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
- <DigestValue>$digest</DigestValue>
- </Reference>};
+ return qq{<dsig:Reference URI="#$id">
+ <dsig:Transforms>
+ <dsig:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
+ <dsig:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
+ </dsig:Transforms>
+ <dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
+ <dsig:DigestValue>$digest</dsig:DigestValue>
+ </dsig:Reference>};
}
sub _canonicalize_xml {
@@ -449,7 +571,7 @@ sub _canonicalize_xml {
elsif ( $self->{ canonicalizer } eq 'XML::CanonicalizeXML' ) {
require XML::CanonicalizeXML;
my $xpath = '<XPath>(//. | //@* | //namespace::*)</XPath>';
- return XML::CanonicalizeXML::canonicalize( $xml, $xpath, [], 0, $comments );
+ return XML::CanonicalizeXML::canonicalize( $xml, $xpath, [], 1, $comments );
}
else {
confess "Unknown XML canonicalizer module.";
@@ -643,6 +765,13 @@ When using XML::Sig exclusively to verify a signature, no key needs to be
specified during initialization given that the public key should be
transmitted with the signature.
+=item B<signer_cert()>
+
+Following a successful verify with an X509 certificate, returns the
+signer's certificate as embedded in the XML document for verification
+against a CA certificate. The certificate is returned as a
+Crypt::OpenSSL::X509 object.
+
=cut
=head2 OPTIONS
@@ -657,6 +786,13 @@ File::Download object.
The path to a file containing the contents of a private key. This option
is used only when generating signatures.
+=item B<cert>
+
+The path to a file containing a PEM-formatted X509 certificate. This
+option is used only when generating signatures with the "x509"
+option. This certificate will be embedded in the signed document, and
+should match the private key used for the signature.
+
=item B<canonicalizer>
The XML canonicalization library to use. Options currently are:
@@ -671,9 +807,9 @@ The XML canonicalization library to use. Options currently are:
=item B<x509>
-Takes a true (1) or false (0) value and indicates how you want the
-signature to be encoded. When true, an X509 certificate will be
-encoded in the signature. Otherwise the native encoding format for
+Takes a true (1) or false (0) value and indicates how you want the
+signature to be encoded. When true, the X509 certificate supplied will
+be encoded in the signature. Otherwise the native encoding format for
RSA and DSA will be used.
=back
View
4 t/005_rsakeys.t
@@ -17,6 +17,6 @@ my $sig = XML::Sig->new( { key => 't/rsa.private.key' } );
isa_ok( $sig, 'XML::Sig' );
isa_ok( $sig->{ key_obj }, 'Crypt::OpenSSL::RSA', 'Key object is valid' );
-is( index( $sig->{KeyInfo}, $modulus ), 41, 'Modulus is correct' );
-is( index( $sig->{KeyInfo}, $exponent), 405, 'Exponent is correct' );
+is( index( $sig->{KeyInfo}, $modulus ), 166, 'Modulus is correct' );
+is( index( $sig->{KeyInfo}, $exponent), 576, 'Exponent is correct' );
View
7 t/006_signing.t
@@ -28,15 +28,12 @@ ok( encode_base64( $signed,'' ), $signed_b64 );
my $is_valid = $sig->verify( $signed );
ok( $is_valid == 1);
-my $sig2 = XML::Sig->new( { key => 't/rsa.private.key', x509 => 1 } );
+my $sig2 = XML::Sig->new( { key => 't/rsa.private.key', cert => 't/rsa.cert.pem', x509 => 1 } );
isa_ok( $sig2, 'XML::Sig' );
my $signed2 = $sig2->sign($xml);
ok( encode_base64( $signed2,'' ), $signed2_b64 );
-TODO: {
-local $TODO = 'OpenSSL base64 decode problem';
-my $is_valid2 = eval { $sig2->verify( $signed2 ) } || 0;
+my $is_valid2 = $sig2->verify( $signed2 );
ok( $is_valid2 == 1 );
-}
my $sig3 = XML::Sig->new( { key => 't/dsa.private.key' } );
isa_ok( $sig3, 'XML::Sig' );
View
25 t/007_verify_saml.t
@@ -0,0 +1,25 @@
+# -*- perl -*-
+
+use strict;
+use warnings;
+
+use Test::More;
+use Test::Exception;
+use MIME::Base64;
+
+BEGIN {
+ use_ok( 'XML::Sig' );
+}
+
+open my $file, 't/saml_response.xml' or die "no test saml response";
+my $xml;
+{
+ local undef $/;
+ $xml = <$file>;
+}
+my $sig = XML::Sig->new({ x509 => 1 });
+my $ret = $sig->verify($xml);
+ok($ret);
+ok($sig->signer_cert);
+
+done_testing;
View
27 t/008_sign_saml.t
@@ -0,0 +1,27 @@
+# -*- perl -*-
+
+use strict;
+use warnings;
+use Test::More;
+
+BEGIN {
+ use_ok( 'XML::Sig' );
+}
+
+open my $file, 't/saml_request.xml' or die "no test saml request";
+my $xml;
+{
+ local undef $/;
+ $xml = <$file>;
+}
+
+my $sig = XML::Sig->new({ x509 => 1, key => 't/rsa.private.key', cert => 't/rsa.cert.pem' });
+my $signed_xml = $sig->sign($xml);
+ok($signed_xml);
+
+my $sig2 = XML::Sig->new({ x509 => 1 });
+my $ret = $sig2->verify($signed_xml);
+ok($ret);
+ok($sig2->signer_cert);
+
+done_testing;
View
40 t/009_verify_separate_cert.t
@@ -0,0 +1,40 @@
+# -*- perl -*-
+
+use strict;
+use warnings;
+
+use Test::More;
+use Test::Exception;
+use MIME::Base64;
+
+BEGIN {
+ use_ok( 'XML::Sig' );
+}
+
+open my $file, 't/logout_response.xml' or die "no test saml logout response";
+my $xml;
+{
+ local undef $/;
+ $xml = <$file>;
+}
+close $file;
+
+my $sig = XML::Sig->new({ x509 => 1, cert => 't/sso.cert.pem' });
+my $ret = $sig->verify($xml);
+ok($ret);
+ok($sig->signer_cert);
+
+open $file, 't/sso.cert.pem';
+my $text;
+{
+ local undef $/;
+ $text = <$file>;
+}
+close $file;
+
+$sig = XML::Sig->new({ x509 => 1, cert_text => $text });
+$ret = $sig->verify($xml);
+ok($ret);
+ok($sig->signer_cert);
+
+done_testing;
View
25 t/logout_response.xml
@@ -0,0 +1,25 @@
+<soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/"><soap-env:Body><samlp:LogoutResponse xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" ID="sd8de04dca9ee5acc72d3f047b2b434e20a1b8a6b" InResponseTo="21B78E9C6C8ECF16F01E4A0F15AB2D46" IssueInstant="2010-10-07T07:36:27Z" Version="2.0">
+<saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">http://openam.nodnol.org:8080/opensso</saml:Issuer><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="#sd8de04dca9ee5acc72d3f047b2b434e20a1b8a6b">
+<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>fwaRmucO1+jis6PQGzKJ6exYo4M=</ds:DigestValue>
+</ds:Reference>
+</ds:SignedInfo>
+<ds:SignatureValue>
+TED3k3U9ho1+vCWk09WnkhcIPMRYlMwJE0InO5Vww9p/vz1LfkL8p5jNivPD/qSmoPczrMFehI/k
+31HxjDGbX3qpqypbovQAvT9j2GOm/4hR5qR4U2LNxXl0Umw2Zi1ntZpcONBtc3BFqxJ3xM6Cwv2U
+y0ubt2L6xc9KRu2BVo0=
+</ds:SignatureValue>
+</ds:Signature>
+<samlp:Status>
+<samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success">
+</samlp:StatusCode>
+</samlp:Status>
+</samlp:LogoutResponse></soap-env:Body></soap-env:Envelope>
View
10 t/saml_request.xml
@@ -0,0 +1,10 @@
+<samlp:ArtifactResolve
+ xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
+ xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
+ ID="_cce4ee769ed970b501d680f697989d14"
+ IssueInstant="2010-09-18T17:33:01Z"
+ Version="2.0">
+ <!-- this is a comment - we can still sign and verify -->
+ <saml:Issuer>http://dev/cgi-bin/zxidhlo.pl?o=B</saml:Issuer>
+ <samlp:Artifact>AAQAALN+k3vq4G80Xko1XPLwwxsvPbU/JPFWdERp73EBAjuV4yT7ce9UMDQ=</samlp:Artifact>
+</samlp:ArtifactResolve>
View
45 t/saml_response.xml
@@ -0,0 +1,45 @@
+<saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="s227ad1998f82a10377ac96ad766cecc1c4a32243c" IssueInstant="2010-09-16T12:49:41Z" Version="2.0">
+<saml:Issuer>http://openam.nodnol.org:8080/opensso</saml:Issuer><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:CanonicalizationMethod>
+<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"></ds:SignatureMethod>
+<ds:Reference URI="#s227ad1998f82a10377ac96ad766cecc1c4a32243c">
+<ds:Transforms>
+<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"></ds:Transform>
+<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"></ds:Transform>
+</ds:Transforms>
+<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
+<ds:DigestValue>S84coogDx7tiP5j2gogV46kgZgo=</ds:DigestValue>
+</ds:Reference>
+</ds:SignedInfo>
+<ds:SignatureValue>
+oEEq4dpVudJ17AqEkl+rf2lFpiLqv/SJMggaBilmg7/WuXI+fTn3+185iIHnK8qxv4d97Uy4rXXA
+KvutzluUhfAX1THLzFur/YmaTQt8j580uBWoPKZYkCCXARYkUrmQsiDXK7xrbyRFwBCUR03YkfaF
+ubVGqu9fxK3uCp09OAg=
+</ds:SignatureValue>
+<ds:KeyInfo>
+<ds:X509Data>
+<ds:X509Certificate>
+MIICQDCCAakCBEeNB0swDQYJKoZIhvcNAQEEBQAwZzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNh
+bGlmb3JuaWExFDASBgNVBAcTC1NhbnRhIENsYXJhMQwwCgYDVQQKEwNTdW4xEDAOBgNVBAsTB09w
+ZW5TU08xDTALBgNVBAMTBHRlc3QwHhcNMDgwMTE1MTkxOTM5WhcNMTgwMTEyMTkxOTM5WjBnMQsw
+CQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEUMBIGA1UEBxMLU2FudGEgQ2xhcmExDDAK
+BgNVBAoTA1N1bjEQMA4GA1UECxMHT3BlblNTTzENMAsGA1UEAxMEdGVzdDCBnzANBgkqhkiG9w0B
+AQEFAAOBjQAwgYkCgYEArSQc/U75GB2AtKhbGS5piiLkmJzqEsp64rDxbMJ+xDrye0EN/q1U5Of+
+RkDsaN/igkAvV1cuXEgTL6RlafFPcUX7QxDhZBhsYF9pbwtMzi4A4su9hnxIhURebGEmxKW9qJNY
+Js0Vo5+IgjxuEWnjnnVgHTs1+mq5QYTA7E6ZyL8CAwEAATANBgkqhkiG9w0BAQQFAAOBgQB3Pw/U
+QzPKTPTYi9upbFXlrAKMwtFf2OW4yvGWWvlcwcNSZJmTJ8ARvVYOMEVNbsT4OFcfu2/PeYoAdiDA
+cGy/F2Zuj8XJJpuQRSE6PtQqBuDEHjjmOQJ0rV/r8mO1ZCtHRhpZ5zYRjhRC9eCbjx9VrFax0JDC
+/FfwWigmrW0Y0Q==
+</ds:X509Certificate>
+</ds:X509Data>
+</ds:KeyInfo>
+</ds:Signature><saml:Subject>
+<saml:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent" NameQualifier="http://openam.nodnol.org:8080/opensso">pDoyCspPDidz0sumzdTONHNumUFc</saml:NameID><saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
+<saml:SubjectConfirmationData InResponseTo="N1Vjstvn7kh30K9PxDlNRiWZf" NotOnOrAfter="2010-09-16T12:59:41Z" Recipient="http://dev/cgi-bin/zxidhlo.pl"></saml:SubjectConfirmationData></saml:SubjectConfirmation>
+</saml:Subject><saml:Conditions NotBefore="2010-09-16T12:39:41Z" NotOnOrAfter="2010-09-16T12:59:41Z">
+<saml:AudienceRestriction>
+<saml:Audience>http://dev/cgi-bin/zxidhlo.pl?o=B</saml:Audience>
+</saml:AudienceRestriction>
+</saml:Conditions>
+<saml:AuthnStatement AuthnInstant="2010-09-16T12:49:41Z" SessionIndex="s23e0618406ade619eaf6810cce29c100b676fca01"><saml:AuthnContext><saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml:AuthnContextClassRef></saml:AuthnContext></saml:AuthnStatement></saml:Assertion>
View
16 t/sso.cert.pem
@@ -0,0 +1,16 @@
+-----BEGIN CERTIFICATE-----
+MIIDDDCCAfSgAwIBAgIBBDANBgkqhkiG9w0BAQUFADA3MQswCQYDVQQGEwJVUzEOMAwGA1UECgwF
+bG9jYWwxCzAJBgNVBAsMAmN0MQswCQYDVQQDDAJDQTAeFw0xMDEwMDYxNDE5MDJaFw0xMTEwMDYx
+NDE5MDJaMGMxCzAJBgNVBAYTAkdCMQ8wDQYDVQQIEwZMb25kb24xDzANBgNVBAcTBkxvbmRvbjEO
+MAwGA1UEChMFVmVuZGExDDAKBgNVBAsTA1NTTzEUMBIGA1UEAxMLUlNBIE9wZW5TU08wgZ8wDQYJ
+KoZIhvcNAQEBBQADgY0AMIGJAoGBALatk5hsXZA1BVxgFmWsAHna/ok3wMIYAtf2S4pTWlhgYEEt
+z8btVPzOxLQ4eu6zAQHoPvOuZf0/LzQuhDgHVxX2x0BS/f5CfEC1Tx+gcSlINKz5pc1eylERMszX
+HrgJEqc5qJL/hqizrPQSTa5c4P1tOApUGmr5ri3GWs+j/OQhAgMBAAGjezB5MAkGA1UdEwQCMAAw
+LAYJYIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQWBBTJ
+jwYYJePNfPQLlfplEcTJjF4NNzAfBgNVHSMEGDAWgBTWcCDL1HYlBpul6nAYYaX4JGy0FDANBgkq
+hkiG9w0BAQUFAAOCAQEAK37Jlh5FxY4Zzph9Q2lkPwBQpHqSM7WeWjOMlQo2cP3oPpbPMohmZwQn
+cNOdHgxERqJ4C4c+olRwFxxA7D/S90emxn9c/dyv3zQIJtNwguhcEX35MaqEFUGvbqnmJukEzdbJ
+m4FU2FC0qGni7Jkvx/bCmS2xvdf71sR2HKSzqmUHys4PAHJhFCVdQXfROlO+964Oxab/HzFUwDCf
+0wzJVksEB4DhP2sJtUIBJTpwofywMX5qLQuM6qPUJ/lRqpaxPOweKlkC5ndFnPtChc0+ZsJI3sBt
+tz+07qyeZJJ8QNx9pRjKr9G8jtj5lXX+BOWizUt7QBTYNFQgWibMs3Ekmg==
+-----END CERTIFICATE-----

No commit comments for this range

Something went wrong with that request. Please try again.