File Coverage

blib/lib/XML/Sig.pm
Criterion Covered Total %
statement 594 661 89.8
branch 187 300 62.3
condition 30 42 71.4
subroutine 55 59 93.2
pod 4 4 100.0
total 870 1066 81.6


line stmt bran cond sub pod time code
1 23     23   2929671 use strict;
  23         241  
  23         651  
2 23     23   124 use warnings;
  23         51  
  23         1244  
3              
4             package XML::Sig;
5             our $VERSION = '0.62';
6              
7 23     23   11738 use Encode;
  23         209795  
  23         1716  
8             # ABSTRACT: XML::Sig - A toolkit to help sign and verify XML Digital Signatures
9              
10             # use 'our' on v5.6.0
11 23     23   164 use vars qw($VERSION @EXPORT_OK %EXPORT_TAGS $DEBUG);
  23         57  
  23         1721  
12              
13             $DEBUG = 0;
14              
15 23     23   157 use base qw(Class::Accessor);
  23         66  
  23         12587  
16             XML::Sig->mk_accessors(qw(key));
17              
18              
19 23     23   57404 use Digest::SHA qw(sha1 sha224 sha256 sha384 sha512 hmac_sha1 hmac_sha256 hmac_sha384 hmac_sha512);
  23         71470  
  23         2374  
20 23     23   11522 use Crypt::Digest::RIPEMD160 qw/ripemd160/;
  23         100325  
  23         1287  
21 23     23   16694 use XML::LibXML;
  23         943339  
  23         189  
22 23     23   11496 use MIME::Base64;
  23         10260  
  23         1279  
23 23     23   198 use Carp;
  23         57  
  23         1162  
24              
25              
26 23     23   154 use constant TRANSFORM_ENV_SIG => 'http://www.w3.org/2000/09/xmldsig#enveloped-signature';
  23         73  
  23         1365  
27 23     23   209 use constant TRANSFORM_C14N => 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315';
  23         60  
  23         1103  
28 23     23   143 use constant TRANSFORM_C14N_COMMENTS => 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments';
  23         80  
  23         1106  
29 23     23   133 use constant TRANSFORM_C14N_V1_1 => 'http://www.w3.org/TR/2008/REC-xml-c14n11-20080502';
  23         60  
  23         1245  
30 23     23   135 use constant TRANSFORM_C14N_V1_1_COMMENTS => 'http://www.w3.org/TR/2008/REC-xml-c14n11-20080502#WithComments';
  23         43  
  23         1472  
31 23     23   153 use constant TRANSFORM_EXC_C14N => 'http://www.w3.org/2001/10/xml-exc-c14n#';
  23         64  
  23         1321  
32 23     23   151 use constant TRANSFORM_EXC_C14N_COMMENTS => 'http://www.w3.org/2001/10/xml-exc-c14n#WithComments';
  23         65  
  23         108192  
33              
34       0     sub DESTROY { }
35              
36             $| = 1; # autoflush
37              
38              
39              
40              
41             sub new {
42 681     681 1 572844 my $class = shift;
43 681         1175 my $params = shift;
44 681         1082 my $self = {};
45 681         1389 foreach my $prop ( qw/ key cert cert_text ns id_attr/ ) {
46 3405 100       6628 if ( exists $params->{ $prop } ) {
47 448         1034 $self->{ $prop } = $params->{ $prop };
48             }
49             # else {
50             # confess "You need to provide the $prop parameter!";
51             # }
52             }
53 681         1232 bless $self, $class;
54 681 100       2261 $self->{ 'x509' } = exists $params->{ x509 } ? 1 : 0;
55 681 100       1567 if ( exists $params->{ key_name } ) {
56 18         53 $self->{ key_name } = $params->{ key_name };
57             }
58 681 100       1324 if ( exists $params->{ 'key' } ) {
59 337         945 $self->_load_key( $params->{ 'key' } );
60             }
61 679 100       1782 if ( exists $params->{ 'cert' } ) {
62 108         450 $self->_load_cert_file( $params->{ 'cert' } );
63             }
64 679 100       1561 if ( exists $params->{ 'cert_text' } ) {
65 1         6 $self->_load_cert_text( $params->{ 'cert_text' } );
66             }
67 679 100       1319 if ( exists $params->{ 'hmac_key' } ) {
68 18         55 $self->_load_hmac_key_info;
69             }
70              
71 679 100 100     2055 if ( exists $params->{ sig_hash } && grep { $_ eq $params->{ sig_hash } } ('sha224', 'sha256', 'sha384', 'sha512', 'ripemd160'))
  910         2146  
72             {
73 151         413 $self->{ sig_hash } = $params->{ sig_hash };
74             }
75             else {
76 528         998 $self->{ sig_hash } = 'sha256';
77             }
78              
79 679 100 66     1685 if ( exists $params->{ digest_hash } && grep { $_ eq $params->{ digest_hash } } ('sha1', 'sha224', 'sha256', 'sha384','sha512', 'ripemd160'))
  1224         2278  
80             {
81 204         437 $self->{ digest_hash } = $params->{ digest_hash };
82             }
83             else {
84 475         807 $self->{ digest_hash } = 'sha256';
85             }
86              
87 679 100 100     2440 if (defined $self->{ key_type } && $self->{ key_type } eq 'dsa') {
88 56         258 my $sig_size = $self->{ key_obj }->get_sig_size();
89              
90             # The key size dictates the sig size
91 56 100       146 if ( $sig_size eq 48 ) { # 1024-bit key
92 28         64 $self->{ sig_hash } = 'sha1';
93             } else { # 2048-bit or 3072-bit key
94 28         58 $self->{ sig_hash } = 'sha256';
95             }
96             }
97              
98 679 100 100     1749 if ( exists $params->{ no_xml_declaration } && $params->{ no_xml_declaration } == 1 ) {
99 1         6 $self->{ no_xml_declaration } = 1;
100             } else {
101 678         1375 $self->{ no_xml_declaration } = 0;
102             }
103              
104 679 100 100     2339 if ( !defined $self->{ key_type } && exists $params->{ hmac_key } ) {
105 18         36 $self->{ hmac_key } = $params->{ hmac_key };
106 18         52 $self->{ key_type } = 'hmac';
107             }
108              
109 679         13416 return $self;
110             }
111              
112              
113             sub sign {
114 338     338 1 141038 my $self = shift;
115 338         819 my ($xml) = @_;
116              
117 338 100 100     1266 die "You cannot sign XML without a private key." unless $self->key || $self->{ hmac_key };
118              
119 337         5064 local $XML::LibXML::skipXMLDeclaration = $self->{ no_xml_declaration };
120              
121 337         1907 my $dom = XML::LibXML->load_xml( string => $xml );
122              
123 337         93478 $self->{ parser } = XML::LibXML::XPathContext->new($dom);
124 337         2525 $self->{ parser }->registerNs('dsig', 'http://www.w3.org/2000/09/xmldsig#');
125 337         1142 $self->{ parser }->registerNs('ec', 'http://www.w3.org/2001/10/xml-exc-c14n#');
126 337         1061 $self->{ parser }->registerNs('saml', 'urn:oasis:names:tc:SAML:2.0:assertion');
127 337 100       899 if ($self->{ns}) {
128 1         2 foreach (keys %{$self->{ns}}) {
  1         27  
129 1         8 $self->{ parser }->registerNs($_, $self->{ns}{$_});
130             }
131             }
132              
133 337 50       785 print ("Signing XML\n") if $DEBUG;
134              
135 337         885 my @ids_to_sign = $self->_get_ids_to_sign();
136              
137 337         828 foreach my $signid (@ids_to_sign) {
138              
139 345 50       1061 print ("Signing ID $signid\n") if $DEBUG;
140              
141             # Temporarily create the Signature XML from the part
142             # TODO: ths section needs a rewrite to create the xml in
143             # a better way.
144              
145             # Create a Reference xml fragment including digest section
146 345         1374 my $digest_xml = $self->_reference_xml( $signid, "REPLACE DIGEST " . $signid );
147              
148             # Create a SignedInfo xml fragment including digest section
149 345         1026 my $signed_info = $self->_signedinfo_xml( $digest_xml );
150              
151             # Create a Signature xml fragment including SignedInfo section
152 345         1037 my $signature_xml = $self->_signature_xml( $signed_info, 'REPLACE SIGNATURE ' . $signid );
153              
154 345 50       898 print ("Sign ID: $signid\n") if $DEBUG;
155              
156             # Get the XML note to sign base on the ID
157 345         824 my $xml = $self->_get_xml_to_sign($signid);
158              
159             # Set the namespace but do not apply it to the XML
160 345         1257 $xml->setNamespace("http://www.w3.org/2000/09/xmldsig#", "dsig", 0);
161              
162             # Canonicalize the XML to http://www.w3.org/2001/10/xml-exc-c14n#
163             # TODO Change the Canonicalization method in the xml fragment from _signedinfo_xml
164             #
165             #
166 345         5402 my $xml_canon = $xml->toStringEC14N();
167              
168 345 100       37449 if(my $ref = Digest::SHA->can($self->{ digest_hash })) {
    50          
169 311         759 $self->{digest_method} = $ref;
170             }
171             elsif ( $ref = Crypt::Digest::RIPEMD160->can($self->{ digest_hash })) {
172 34         111 $self->{digest_method} = $ref;
173             }
174             else {
175 0         0 die("Can't handle $self->{ digest_hash }");
176             }
177              
178             # Calculate the digest of the XML being signed
179 345         1184 my $bin_digest = $self->{digest_method}->( Encode::encode_utf8( $xml_canon ));
180 345         6883 my $digest = encode_base64( $bin_digest, '' );
181 345 50       921 print (" Digest: $digest\n") if $DEBUG;
182              
183             # Display the ID of the XML being signed for debugging
184 345         555 my $reference = $signid; #$self->{parser}->findvalue('//@ID', $xml);
185 345 50       722 print (" Reference URI: $reference\n") if $DEBUG;
186              
187             # Add the Signature to the xml being signed
188 345         1212 $xml->appendWellBalancedChunk($signature_xml, 'UTF-8');
189              
190             # Canonicalize the SignedInfo to http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments
191             # TODO Change the Canonicalization method in the xml fragment from _signedinfo_xml
192              
193 345         75299 my ($signature_node) = $xml->findnodes(
194             './dsig:Signature', $xml);
195 345         12414 my ($signed_info_node) = $xml->findnodes(
196             './dsig:Signature/dsig:SignedInfo',$xml);
197              
198             # Add the digest value to the Signed info
199 345         9239 my ($digest_value_node) = $xml->findnodes(
200             './dsig:Signature/dsig:SignedInfo/dsig:Reference/dsig:DigestValue', $signature_node);
201 345         10248 $digest_value_node->removeChildNodes();
202 345         1465 $digest_value_node->appendText($digest);
203              
204             # At this point the SignedInfo includes the information
205             # to allow us to use the _canonicalize_xml with the $signature_node
206 345         1749 my $signed_info_canon = $self->_canonicalize_xml($signed_info_node, $signature_node);
207              
208             # Calculate the signature of the Canonical Form of SignedInfo
209 345         6436 my $signature;
210 345 100       1377 if ($self->{key_type} eq 'dsa') {
    100          
    100          
211 58         176 $signature = encode_base64( $self->_calc_dsa_signature( $signed_info_canon ), "\n" );
212             } elsif ($self->{key_type} eq 'ecdsa') {
213 172         559 $signature = encode_base64( $self->_calc_ecdsa_signature( $signed_info_canon ), "\n" );
214             } elsif ($self->{key_type} eq 'rsa') {
215 109         293 $signature = encode_base64( $self->_calc_rsa_signature( $signed_info_canon ), "\n" );
216             } else {
217 6 50       15 if ( defined $self->{ hmac_key } ) {
218 6         19 $signature = encode_base64( $self->_calc_hmac_signature( $signed_info_canon ), "\n" );
219             } else {
220 0         0 die "No Signature signing method provided";
221             }
222             }
223              
224             # Add the Signature to the SignatureValue
225 345         1540 my ($signature_value_node) = $xml->findnodes(
226             './dsig:Signature/dsig:SignatureValue', $signature_node);
227 345         15156 $signature_value_node->removeChildNodes();
228 345         1756 $signature_value_node->appendText($signature);
229              
230 345 50       1584 print ("\n\n\n SignatureValue:\n" . $signature_value_node . "\n\n\n") if $DEBUG;
231             }
232              
233 337         15744 return $dom->toString;
234             }
235              
236              
237             sub verify {
238 356     356 1 14577 my $self = shift;
239 356         639 delete $self->{signer_cert};
240 356         828 my ($xml) = @_;
241              
242 356         1300 my $dom = XML::LibXML->load_xml( string => $xml );
243              
244 356         104414 $self->{ parser } = XML::LibXML::XPathContext->new($dom);
245 356         2553 $self->{ parser }->registerNs('dsig', 'http://www.w3.org/2000/09/xmldsig#');
246 356         1352 $self->{ parser }->registerNs('ec', 'http://www.w3.org/2001/10/xml-exc-c14n#');
247 356         1128 $self->{ parser }->registerNs('saml', 'urn:oasis:names:tc:SAML:2.0:assertion');
248 356         1131 $self->{ parser }->registerNs('ecdsa', 'http://www.w3.org/2001/04/xmldsig-more#');
249              
250 356         1131 my $signature_nodeset = $self->{ parser }->findnodes('//dsig:Signature');
251              
252 356         16680 my $numsigs = $signature_nodeset->size();
253 356 50       2413 print ("NodeSet Size: $numsigs\n") if $DEBUG;
254              
255             # Loop through each Signature in the document checking each
256 356         516 my $i;
257 356         1332 while (my $signature_node = $signature_nodeset->shift()) {
258 369         4632 $i++;
259 369 50       768 print ("\nSignature $i\n") if $DEBUG;
260              
261             # Get SignedInfo Reference ID
262             my $reference = $self->{ parser }->findvalue(
263 369         1038 'dsig:SignedInfo/dsig:Reference/@URI', $signature_node);
264 369         31293 $reference =~ s/#//g;
265              
266 369 50       1170 print (" Reference URI: $reference\n") if $DEBUG;
267              
268             # The reference ID must point to something in the document
269             # if not disregard it and look for another signature
270             # TODO check to ensure that if there is only a single reference
271             # like this it won't accidentally validate
272 369 100       1580 if (! $self->{ parser }->findvalue('//*[@ID=\''. $reference . '\']')) {
273 2 50       220 print (" Signature reference $reference is not signing anything in this xml\n") if $DEBUG;
274 2 100       7 if ($numsigs <= 1) {
275 1         6 return 0;
276             }
277             else {
278 1         4 next;
279             }
280             }
281              
282             # Get SignedInfo DigestMethod Algorithim
283             my $digest_method = $self->{ parser }->findvalue(
284 367         36424 'dsig:SignedInfo/dsig:Reference/dsig:DigestMethod/@Algorithm', $signature_node);
285 367         33308 $digest_method =~ s/^.*[#]//;
286 367 50       1111 print (" Digest Method: $digest_method\n") if $DEBUG;
287              
288             # Get the DigestValue used to verify Canonical XML
289             # Note that the digest may have embedded newlines in the XML
290             # Decode the base64 and encode it with no newlines
291             my $refdigest = encode_base64(decode_base64(_trim($self->{ parser }->findvalue(
292 367         1118 'dsig:SignedInfo/dsig:Reference/dsig:DigestValue', $signature_node))), "");
293 367 50       1268 print (" Digest Value: $refdigest\n") if $DEBUG;
294              
295             # Get the SignatureValue used to verify the SignedInfo
296 367         5287 my $signature = _trim($self->{ parser }->findvalue('dsig:SignatureValue', $signature_node));
297 367 50       1307 print (" Signature: $signature\n") if $DEBUG;
298              
299             # Get SignatureMethod Algorithim
300             my $signature_method = $self->{ parser }->findvalue(
301 367         5153 'dsig:SignedInfo/dsig:SignatureMethod/@Algorithm', $signature_node);
302 367         25908 $signature_method =~ s/^.*[#]//;
303 367         1148 $signature_method =~ s/^rsa-//;
304 367         897 $signature_method =~ s/^dsa-//;
305 367         976 $signature_method =~ s/^ecdsa-//;
306 367         648 $signature_method =~ s/^hmac-//;
307              
308 367         797 $self->{ sig_hash } = $signature_method;
309 367 50       789 print (" SignatureMethod: $signature_method\n") if $DEBUG;
310              
311             # Get the SignedInfo and obtain its Canonical form
312 367         987 my ($signed_info) = $self->{ parser }->findnodes('dsig:SignedInfo', $signature_node);
313 367         14319 my $signed_info_canon = $self->_canonicalize_xml($signed_info, $signature_node);
314              
315 367 50       6057 print "$signed_info_canon\n" if $DEBUG;
316              
317 367 100       2776 if(my $ref = Digest::SHA->can($signature_method)) {
    50          
318 341         977 $self->{sig_method} = $ref;
319             }
320             elsif ( $ref = Crypt::Digest::RIPEMD160->can( $signature_method )) {
321 26         64 $self->{sig_method} = $ref;
322             }
323             else {
324 0         0 die("Can't handle $signature_method");
325             }
326              
327 367 100       1878 if(my $ref = Digest::SHA->can($digest_method)) {
    50          
328 333         644 $self->{digest_method} = $ref;
329             }
330             elsif ( $ref = Crypt::Digest::RIPEMD160->can( $digest_method )) {
331 34         126 $self->{digest_method} = $ref;
332             }
333             else {
334 0         0 die("Can't handle $digest_method");
335             }
336              
337             # If a cert was provided to XML::Sig->new() use it to
338             # verify the SignedInfo signature
339 367 100 66     2085 if (defined $self->{cert_obj}) {
    100          
340             # use the provided cert to verify
341 16 50       62 unless ($self->_verify_x509_cert($self->{cert_obj},$signed_info_canon,$signature)) {
342 0         0 print STDERR "not verified by x509\n";
343 0         0 return 0;
344             }
345             }
346             elsif (!defined $self->{cert_obj} && defined $self->{ hmac_key }) {
347             # use the provided cert to verify
348 12 100       47 unless ($self->_verify_hmac($signed_info_canon,$signature)) {
349 6 50       13 print "not verified by hmac-" . $self->{ sig_hash }, "\n" if $DEBUG;
350 6         18 return 0;
351             }
352             }
353             # Extract the XML provided certificate and use it to
354             # verify the SignedInfo signature
355             else {
356             # extract the certficate or key from the document
357 339         1585 my %verify_dispatch = (
358             'X509Data' => '_verify_x509',
359             'RSAKeyValue' => '_verify_rsa',
360             'DSAKeyValue' => '_verify_dsa',
361             'ECDSAKeyValue' => '_verify_ecdsa',
362             );
363 339         479 my $keyinfo_nodeset;
364 339         642 foreach my $key_info_sig_type ( qw/X509Data RSAKeyValue DSAKeyValue ECDSAKeyValue/ ) {
365 872 100       3748 if ( $key_info_sig_type eq 'X509Data' ) {
366             $keyinfo_nodeset = $self->{ parser }->find(
367 339         1319 "dsig:KeyInfo/dsig:$key_info_sig_type", $signature_node);
368             #print (" keyinfo_nodeset X509Data: $keyinfo_nodeset\n") if $DEBUG;
369             } else {
370             $keyinfo_nodeset = $self->{ parser }->find(
371 533         1530 "dsig:KeyInfo/dsig:KeyValue/dsig:$key_info_sig_type", $signature_node);
372             #print (" keyinfo_nodeset [DR]SAKeyValue: $keyinfo_nodeset\n") if $DEBUG;
373             }
374 872 100       37015 if ( $keyinfo_nodeset->size ) {
375 339         1891 my $verify_method = $verify_dispatch{$key_info_sig_type};
376 339 50       742 print (" Verify Method: $verify_method\n") if $DEBUG;
377 339 50       922 if ( ! $self->$verify_method($keyinfo_nodeset->get_node(0),
378             $signed_info_canon, $signature) ) {
379 0 0       0 print ("keyinfo_nodeset->get_node: " . $keyinfo_nodeset->get_node(0) . "\n") if $DEBUG;
380 0         0 print STDERR "Failed to verify using $verify_method\n";
381 0         0 return 0;
382             } else {
383 339 50       1201 print ("Success Verifying\n") if $DEBUG;
384             }
385 339         781 last;
386             }
387             }
388 339 50 33     1451 die "Unrecognized key type or no KeyInfo in document" unless (
389             $keyinfo_nodeset && $keyinfo_nodeset->size > 0);
390             }
391              
392             # Signature of SignedInfo was verified above now obtain the
393             # Canonical form of the XML and verify the DigestValue of the XML
394              
395             # Remove the Signature from the signed XML
396 361         19721 my $signed_xml = $self->_get_signed_xml( $signature_node );
397 361         4115 $signed_xml->removeChild( $signature_node );
398              
399             # Obtain the Canonical form of the XML
400 361         1135 my $canonical = $self->_transform($signed_xml, $signature_node);
401              
402             # Add the $signature_node back to the $signed_xml to allow other
403             # signatures to be validated if they exist
404 361         10008 $signed_xml->addChild( $signature_node );
405              
406 361 50       861 print ( " Canonical XML: " . $canonical ."\n") if $DEBUG;
407              
408             # Obtain the DigestValue of the Canonical XML
409 361         4558 my $digest = $self->{digest_method}->(Encode::encode_utf8($canonical));
410              
411 361 50       6441 print ( " Reference Digest: " . _trim($refdigest) ."\n") if $DEBUG;
412              
413 361 50       680 print ( " Calculated Digest: ". _trim(encode_base64($digest, '')) ."\n") if $DEBUG;
414              
415             # Return 0 - fail verification on the first XML signature that fails
416 361 50       1471 return 0 unless ($refdigest eq _trim(encode_base64($digest, '')));
417              
418 361 50       1316 print ( "Signature $i Valid\n") if $DEBUG;
419             }
420              
421 349         11493 return 1;
422             }
423              
424              
425             sub signer_cert {
426 12     12 1 6087 my $self = shift;
427 12         47 return $self->{signer_cert};
428             }
429              
430             ##
431             ## _get_ids_to_sign()
432             ##
433             ## Arguments:
434             ##
435             ## Returns: array Value of ID attributes from XML
436             ##
437             ## Finds all the values of the ID attributes in the XML
438             ## and return them in reverse order found. Reverse order
439             ## assumes that the Signatures should be performed on lower
440             ## Nodes first.
441             ##
442             sub _get_ids_to_sign {
443 337     337   499 my $self = shift;
444              
445 337 100       889 if ($self->{id_attr}) {
446 1         6 my $nodes = $self->{parser}->findnodes($self->{id_attr});
447 1 50       51 if ($nodes->size == 0) {
448 0         0 die "Unable to find an attribute node with $self->{id_attr}";
449             }
450 1         15 my $node = $nodes->get_node(1);
451 1         11 return $node->getAttribute('ID');
452              
453             }
454              
455 336         1223 my @id = $self->{parser}->findnodes('//@ID');
456 336         14378 my @ids;
457 336         745 foreach (@id) {
458 344         658 my $i = $_;
459 344         2013 $_ =~ m/^.*\"(.*)\".*$/;
460 344         6346 $i = $1;
461             #//*[@ID='identifier_1']
462 344 50       804 die "You cannot sign an XML document without identifying the element to sign with an ID attribute" unless $i;
463 344         1098 unshift @ids, $i;
464             }
465 336         1721 return @ids;
466              
467              
468             }
469              
470             ##
471             ## _get_xml_to_sign()
472             ##
473             ## Arguments:
474             ## $id: string ID of the Node for the XML to retrieve
475             ##
476             ## Returns: XML NodeSet to sign
477             ##
478             ## Find the XML node with the ID = $id and return the
479             ## XML NodeSet
480             ##
481             sub _get_xml_to_sign {
482 345     345   675 my $self = shift;
483 345         594 my $id = shift;
484 345 50       704 die "You cannot sign an XML document without identifying the element to sign with an ID attribute" unless $id;
485              
486 345         773 my $xpath = "//*[\@ID='$id']";
487 345         882 my ($node) = $self->_get_node( $xpath );
488 345         806 return $node;
489             }
490              
491             ##
492             ## _get_signed_xml($context)
493             ##
494             ## Arguments:
495             ## $context: string XML NodeSet used as context
496             ##
497             ## Returns: XML NodeSet for with ID equal to the URI
498             ##
499             ## Find the XML node with the ID = $URI and return the
500             ## XML NodeSet
501             ##
502             sub _get_signed_xml {
503 361     361   630 my $self = shift;
504 361         634 my ($context) = @_;
505              
506 361         1064 my $id = $self->{parser}->findvalue('./dsig:SignedInfo/dsig:Reference/@URI', $context);
507 361         30647 $id =~ s/^#//;
508 361 50       1129 print (" Signed XML id: $id\n") if $DEBUG;
509              
510 361         1208 $self->{'sign_id'} = $id;
511 361         1010 my $xpath = "//*[\@ID='$id']";
512 361         1101 return $self->_get_node( $xpath, $context );
513             }
514              
515             ##
516             ## _transform($xml, $context)
517             ##
518             ## Arguments:
519             ## $xml: string XML NodeSet
520             ## $context: string XML Context
521             ##
522             ## Returns: string Transformed XML
523             ##
524             ## Canonicalizes/Transforms xml based on the Transforms
525             ## from the SignedInfo.
526             ##
527             sub _transform {
528 361     361   4920 my $self = shift;
529 361         735 my ($xml, $context) = @_;
530              
531 361         995 $context->setNamespace( 'http://www.w3.org/2000/09/xmldsig#', 'dsig' );
532             my $transforms = $self->{parser}->find(
533 361         6682 'dsig:SignedInfo/dsig:Reference/dsig:Transforms/dsig:Transform',
534             $context
535             );
536              
537 361 50       17321 print "_transform\n" if $DEBUG;
538 361         920 foreach my $node ($transforms->get_nodelist) {
539 722         2775 my $alg = $node->getAttribute('Algorithm');
540              
541 722 50       7371 print " Algorithm: $alg\n" if $DEBUG;
542 722 100       2479 if ($alg eq TRANSFORM_ENV_SIG) {
    50          
    50          
    50          
    0          
543             # TODO the xml being passed here currently has the
544             # Signature removed. May be better to do it all here
545 361         680 next;
546             }
547             elsif ($alg eq TRANSFORM_C14N) {
548 0 0       0 print " toStringC14N" if $DEBUG;
549 0         0 $xml = $xml->toStringC14N();
550             }
551             elsif ($alg eq TRANSFORM_C14N_COMMENTS) {
552 0 0       0 print " toStringC14N(1)" if $DEBUG;
553 0         0 $xml = $xml->toStringC14N(1);
554             }
555             elsif ($alg eq TRANSFORM_EXC_C14N) {
556 361         871 my @prefixlist = $self->_find_prefixlist($node);
557 361 50       854 print " toStringEC14N(0, '', @prefixlist)\n" if $DEBUG;
558 361         1052 $xml = $xml->toStringEC14N(0, '', \@prefixlist);
559             }
560             elsif ($alg eq TRANSFORM_EXC_C14N_COMMENTS) {
561 0         0 my @prefixlist = $self->_find_prefixlist($node);
562 0 0       0 print " toStringEC14N(1, '', @prefixlist)\n" if $DEBUG;
563 0         0 $xml = $xml->toStringEC14N(1, '', \@prefixlist);
564             }
565             else {
566 0         0 die "Unsupported transform: $alg";
567             }
568             }
569 361         37634 return $xml;
570             }
571              
572             ##
573             ## _find_prefixlist($node)
574             ##
575             ## Arguments:
576             ## $node: string XML NodeSet
577             ##
578             ## Returns: ARRAY of prefix lists
579             ##
580             ## Generate an array of prefix lists defined in InclusiveNamespaces
581             ##
582             sub _find_prefixlist {
583 361     361   621 my $self = shift;
584 361         621 my ($node) = @_;
585 361         896 my @children = $node->getChildrenByLocalName('InclusiveNamespaces');
586              
587 361         3385 my $prefixlist = '';
588 361         781 foreach my $child (@children) {
589 4 50       13 if ($child) {
590 4         37 $prefixlist .= $child->getAttribute('PrefixList');
591             }
592 4         52 $prefixlist .= ' ';
593             }
594 361         996 return split / /, $prefixlist;
595             }
596              
597             ##
598             ## _verify_rsa($context,$canonical,$sig)
599             ##
600             ## Arguments:
601             ## $context: string XML Context to use
602             ## $canonical: string Canonical XML to verify
603             ## $sig: string Base64 encode of RSA Signature
604             ##
605             ## Returns: integer (1 True, 0 False) if signature is valid
606             ##
607             ## Verify the RSA signature of Canonical XML
608             ##
609             sub _verify_rsa {
610 53     53   438 my $self = shift;
611 53         120 my ($context,$canonical,$sig) = @_;
612              
613             # Generate Public Key from XML
614 53         149 my $mod = _trim($self->{parser}->findvalue('dsig:Modulus', $context));
615 53         191 my $modBin = decode_base64( $mod );
616 53         910 my $exp = _trim($self->{parser}->findvalue('dsig:Exponent', $context));
617 53         170 my $expBin = decode_base64( $exp );
618 53         939 my $n = Crypt::OpenSSL::Bignum->new_from_bin($modBin);
619 53         145 my $e = Crypt::OpenSSL::Bignum->new_from_bin($expBin);
620 53         1599 my $rsa_pub = Crypt::OpenSSL::RSA->new_key_from_parameters( $n, $e );
621              
622             # Decode signature and verify
623 53         3073 my $sig_hash = 'use_' . $self->{ sig_hash } . '_hash';
624 53         250 $rsa_pub->$sig_hash;
625 53         208 my $bin_signature = decode_base64($sig);
626 53 50       6077 return 1 if ($rsa_pub->verify( $canonical, $bin_signature ));
627 0         0 return 0;
628             }
629              
630             ##
631             ## _clean_x509($cert)
632             ##
633             ## Arguments:
634             ## $cert: string Certificate in base64 from XML
635             ##
636             ## Returns: string Certificate in Valid PEM format
637             ##
638             ## Reformats Certifcate string into PEM format 64 characters
639             ## with proper header and footer
640             ##
641             sub _clean_x509 {
642 107     107   1614 my $self = shift;
643 107         262 my ($cert) = @_;
644              
645 107 50       367 $cert = $cert->value() if(ref $cert);
646 107         256 chomp($cert);
647              
648             # rewrap the base64 data from the certificate; it may not be
649             # wrapped at 64 characters as PEM requires
650 107         2047 $cert =~ s/\n//g;
651              
652 107         289 my @lines;
653 107         1170 while (length $cert > 64) {
654 2183         14596 push @lines, substr $cert, 0, 64, '';
655             }
656 107         263 push @lines, $cert;
657              
658 107         734 $cert = join "\n", @lines;
659              
660 107         462 $cert = "-----BEGIN CERTIFICATE-----\n" . $cert . "\n-----END CERTIFICATE-----\n";
661 107         451 return $cert;
662             }
663              
664             ##
665             ## _verify_x509($context,$canonical,$sig)
666             ##
667             ## Arguments:
668             ## $context: string XML Context to use
669             ## $canonical: string Canonical XML to verify
670             ## $sig: string Base64 encode of RSA Signature
671             ##
672             ## Returns: integer (1 True, 0 False) if signature is valid
673             ##
674             ## Verify the RSA signature of Canonical XML using an X509
675             ##
676             sub _verify_x509 {
677 107     107   965 my $self = shift;
678 107         353 my ($context,$canonical,$sig) = @_;
679              
680 107         171 eval {
681 107         2691 require Crypt::OpenSSL::X509;
682             };
683 107 50       122228 confess "Crypt::OpenSSL::X509 needs to be installed so that we can handle X509 certificates" if $@;
684              
685             # Generate Public Key from XML
686 107         324 my $certificate = _trim($self->{parser}->findvalue('dsig:X509Certificate', $context));
687              
688             # This is added because the X509 parser requires it for self-identification
689 107         411 $certificate = $self->_clean_x509($certificate);
690              
691 107         8742 my $cert = Crypt::OpenSSL::X509->new_from_string($certificate);
692              
693 107         486 return $self->_verify_x509_cert($cert, $canonical, $sig);
694             }
695              
696             ##
697             ## _verify_x509_cert($cert,$canonical,$sig)
698             ##
699             ## Arguments:
700             ## $cert: string X509 Certificate
701             ## $canonical: string Canonical XML to verify
702             ## $sig: string Base64 encode of [EC|R]SA Signature
703             ##
704             ## Returns: integer (1 True, 0 False) if signature is valid
705             ##
706             ## Verify the X509 signature of Canonical XML
707             ##
708             sub _verify_x509_cert {
709 123     123   227 my $self = shift;
710 123         362 my ($cert, $canonical, $sig) = @_;
711              
712             # Decode signature and verify
713 123         517 my $bin_signature = decode_base64($sig);
714              
715 123 100       1457 if ($cert->key_alg_name eq 'id-ecPublicKey') {
    100          
716 50 50       111 eval {require Crypt::PK::ECC; CryptX->VERSION('0.036'); 1}
  50         337  
  50         697  
  50         266  
717             or confess "Crypt::PK::ECC 0.036+ needs to be installed so
718             that we can handle ECDSA signatures";
719 50         4951 my $ecdsa_pub = Crypt::PK::ECC->new(\$cert->pubkey);
720              
721 50         278058 my $ecdsa_hash = $self->{rsa_hash};
722              
723             # Signature is stored as the concatenation of r and s.
724             # verify_message_rfc7518 expects that format
725 50 50       171893 if ($ecdsa_pub->verify_message_rfc7518( $bin_signature, $canonical, uc($self->{sig_hash}) )) {
726 50         406 $self->{signer_cert} = $cert;
727 50         592 return 1;
728             }
729             }
730             elsif ($cert->key_alg_name eq 'dsaEncryption') {
731 2         6 eval {
732 2         13 require Crypt::OpenSSL::DSA;
733             };
734 2 50       12 confess "Crypt::OpenSSL::DSA needs to be installed so
735             that we can handle DSA X509 certificates" if $@;
736              
737 2         168 my $dsa_pub = Crypt::OpenSSL::DSA->read_pub_key_str( $cert->pubkey );
738 2         96 my $sig_size = ($dsa_pub->get_sig_size - 8)/2;
739             #my ($r, $s) = unpack('a20a20', $bin_signature);
740 2         35 my $unpk = "a" . $sig_size . "a" . $sig_size;
741 2         18 my ($r, $s) = unpack($unpk, $bin_signature);
742              
743             # Create a new Signature Object from r and s
744 2         10 my $sigobj = Crypt::OpenSSL::DSA::Signature->new();
745 2         11 $sigobj->set_r($r);
746 2         9 $sigobj->set_s($s);
747              
748 2 50       2720 if ($dsa_pub->do_verify($self->{sig_method}->($canonical), $sigobj)) {
749 2         11 $self->{signer_cert} = $cert;
750 2         29 return 1;
751             }
752             }
753             else {
754 71         150 eval {
755 71         2961 require Crypt::OpenSSL::RSA;
756             };
757 71 50       23977 confess "Crypt::OpenSSL::RSA needs to be installed so
758             that we can handle X509 certificates" if $@;
759              
760 71         3809 my $rsa_pub = Crypt::OpenSSL::RSA->new_public_key($cert->pubkey);
761              
762 71         8491 my $sig_hash = 'use_' . $self->{sig_hash} . '_hash';
763 71         433 $rsa_pub->$sig_hash();
764             # If successful verify, store the signer's cert for validation
765 71 50       7707 if ($rsa_pub->verify( $canonical, $bin_signature )) {
766 71         319 $self->{signer_cert} = $cert;
767 71         596 return 1;
768             }
769             }
770              
771 0         0 return 0;
772             }
773              
774             ##
775             ## _zero_fill_buffer($bits)
776             ##
777             ## Arguments:
778             ## $bits: number of bits to set to zero
779             ##
780             ## Returns: Zero filled bit buffer of size $bits
781             ##
782             ## Create a buffer with all bits set to 0
783             ##
784             sub _zero_fill_buffer {
785 58     58   96 my $bits = shift;
786             # set all bit to zero
787 58         107 my $v = '';
788 58         173 for (my $i = 0; $i < $bits; $i++) {
789 23936         47798 vec($v, $i, 1) = 0;
790             }
791 58         176 return $v;
792             }
793              
794             ##
795             ## _concat_dsa_sig_r_s(\$buffer,$r,$s)
796             ##
797             ## Arguments:
798             ## $buffer: Zero Filled bit buffer
799             ## $r: octet stream
800             ## $s: octet stream
801             ##
802             ## Combine r and s components of DSA signature
803             ##
804             sub _concat_dsa_sig_r_s {
805              
806 58     58   149 my ($buffer, $r, $s, $sig_size) = @_;
807 58         156 my $bits_r = (length($r)*8)-1;
808 58         96 my $bits_s = (length($s)*8)-1;
809              
810 58         126 my $halfsize = $sig_size / 2;
811              
812             # Place $s right justified in $v starting at bit 319
813 58         142 for (my $i = $bits_s; $i >=0; $i--) {
814 11968         26620 vec($$buffer, $halfsize + $i + (($halfsize -1) - $bits_s) , 1) = vec($s, $i, 1);
815             }
816              
817             # Place $r right justified in $v starting at bit 159
818 58         178 for (my $i = $bits_r; $i >= 0 ; $i--) {
819 11968         26338 vec($$buffer, $i + (($halfsize -1) - $bits_r) , 1) = vec($r, $i, 1);
820             }
821              
822             }
823              
824             ##
825             ## _verify_dsa($context,$canonical,$sig)
826             ##
827             ## Arguments:
828             ## $context: string XML Context to use
829             ## $canonical: string Canonical XML to verify
830             ## $sig: string Base64 encode 40 byte string of r and s
831             ##
832             ## Returns: integer (1 True, 0 False) if signature is valid
833             ##
834             ## Verify the DSA signature of Canonical XML
835             ##
836             sub _verify_dsa {
837 57     57   487 my $self = shift;
838 57         135 my ($context,$canonical,$sig) = @_;
839              
840 57         89 eval {
841 57         320 require Crypt::OpenSSL::DSA;
842             };
843 57 50       131 confess "Crypt::OpenSSL::DSA needs to be installed so
844             that we can handle DSA signatures" if $@;
845              
846             # Generate Public Key from XML
847 57         171 my $p = decode_base64(_trim($self->{parser}->findvalue('dsig:P', $context)));
848 57         197 my $q = decode_base64(_trim($self->{parser}->findvalue('dsig:Q', $context)));
849 57         178 my $g = decode_base64(_trim($self->{parser}->findvalue('dsig:G', $context)));
850 57         240 my $y = decode_base64(_trim($self->{parser}->findvalue('dsig:Y', $context)));
851 57         176 my $dsa_pub = Crypt::OpenSSL::DSA->new();
852 57         1038 $dsa_pub->set_p($p);
853 57         264 $dsa_pub->set_q($q);
854 57         213 $dsa_pub->set_g($g);
855 57         177 $dsa_pub->set_pub_key($y);
856              
857             # Decode signature and verify
858 57         141 my $bin_signature = decode_base64($sig);
859              
860             # https://www.w3.org/TR/2002/REC-xmldsig-core-20020212/#sec-SignatureAlg
861             # The output of the DSA algorithm consists of a pair of integers
862             # The signature value consists of the base64 encoding of the
863             # concatenation of r and s in that order ($r . $s)
864             # Binary Signature is stored as a concatenation of r and s
865 57         253 my $sig_size = ($dsa_pub->get_sig_size - 8)/2;
866 57         468 my $unpk = "a" . $sig_size . "a" . $sig_size;
867 57         290 my ($r, $s) = unpack($unpk, $bin_signature);
868              
869             # Create a new Signature Object from r and s
870 57         194 my $sigobj = Crypt::OpenSSL::DSA::Signature->new();
871 57         175 $sigobj->set_r($r);
872 57         182 $sigobj->set_s($s);
873              
874             # DSA signatures are limited to a message body of 20 characters, so a sha1 digest is taken
875 57 50       55164 return 1 if ($dsa_pub->do_verify( $self->{sig_method}->($canonical), $sigobj ));
876 0         0 return 0;
877             }
878              
879             ##
880             ## _verify_ecdsa($context,$canonical,$sig)
881             ##
882             ## Arguments:
883             ## $context: string XML Context to use
884             ## $canonical: string Canonical XML to verify
885             ## $sig: string Base64 encoded
886             ##
887             ## Returns: integer (1 True, 0 False) if signature is valid
888             ##
889             ## Verify the ECDSA signature of Canonical XML
890             ##
891             sub _verify_ecdsa {
892 122     122   1073 my $self = shift;
893 122         372 my ($context,$canonical,$sig) = @_;
894              
895 122 50       202 eval {require Crypt::PK::ECC; CryptX->VERSION('0.036'); 1}
  122         797  
  122         1359  
  122         600  
896             or confess "Crypt::PK::ECC 0.036+ needs to be installed so
897             that we can handle ECDSA signatures";
898             # Generate Public Key from XML
899 122         443 my $oid = _trim($self->{parser}->findvalue('.//dsig:NamedCurve/@URN', $context));
900              
901 23     23   13589 use URI ();
  23         109565  
  23         4721  
902 122         1137 my $u1 = URI->new($oid);
903 122         32472 $oid = $u1->nss;
904              
905 122         3755 my %curve_name = (
906             '1.2.840.10045.3.1.1' => 'secp192r1',
907             '1.3.132.0.33' => 'secp224r1',
908             '1.2.840.10045.3.1.7' => 'secp256r1',
909             '1.3.132.0.34' => 'secp384r1',
910             '1.3.132.0.35' => 'secp521r1',
911             '1.3.36.3.3.2.8.1.1.1' => 'brainpoolP160r1',
912             '1.3.36.3.3.2.8.1.1.3' => 'brainpoolP192r1',
913             '1.3.36.3.3.2.8.1.1.5' => 'brainpoolP224r1',
914             '1.3.36.3.3.2.8.1.1.7' => 'brainpoolP256r1',
915             '1.3.36.3.3.2.8.1.1.9' => 'brainpoolP320r1',
916             '1.3.36.3.3.2.8.1.1.11' => 'brainpoolP384r1',
917             '1.3.36.3.3.2.8.1.1.13' => 'brainpoolP512r1',
918             );
919              
920 122         440 my $x = $self->{parser}->findvalue('.//dsig:PublicKey/dsig:X/@Value', $context);
921 122         9162 my $y = $self->{parser}->findvalue('.//dsig:PublicKey/dsig:Y/@Value', $context);
922              
923 122         7910 my $ecdsa_pub = Crypt::PK::ECC->new();
924              
925             $ecdsa_pub->import_key({
926             kty => "EC",
927 122         7313 curve_name => $curve_name{ $oid },
928             pub_x => $x,
929             pub_y => $y,
930             });
931              
932 122         664571 my $bin_signature = decode_base64($sig);
933              
934             # verify_message_rfc7518 is used to verify signature stored as a
935             # concatenation of integers r and s
936             return 1 if ($ecdsa_pub->verify_message_rfc7518(
937             $bin_signature,
938             $canonical,
939 122 50       423405 uc($self->{sig_hash}))
940             );
941 0         0 return 0;
942             }
943              
944             ##
945             ## _verify_hmac($canonical, $sig)
946             ##
947             ## Arguments:
948             ## $canonical: string Canonical XML to verify
949             ## $sig: string Base64 encode of HMAC Signature
950             ##
951             ## Returns: integer (1 True, 0 False) if signature is valid
952             ##
953             ## Verify the HMAC signature of Canonical XML
954             ##
955             sub _verify_hmac {
956 12     12   22 my $self = shift;
957 12         30 my ($canonical, $sig) = @_;
958              
959             # Decode signature and verify
960 12         34 my $bin_signature = decode_base64($sig);
961 23     23   10728 use Crypt::Mac::HMAC qw( hmac );
  23         27486  
  23         71483  
962 12 50       29 if ( defined $self->{ hmac_key } ) {
963 12 50       25 print (" Verifying SignedInfo using hmac-", $self->{ sig_hash }, "\n") if $DEBUG;
964 12 100       113 if ( my $ref = Digest::SHA->can('hmac_' . $self->{ sig_hash }) ) {
    50          
965 10 100       29 if ($bin_signature eq $self->_calc_hmac_signature( $canonical )) {
966 5         21 return 1;
967             }
968             else {
969 5         19 return 0;
970             }
971             }
972             elsif ( $ref = Crypt::Digest::RIPEMD160->can($self->{ sig_hash })) {
973 2 100       7 if ($bin_signature eq $self->_calc_hmac_signature( $canonical )) {
974 1         5 return 1;
975             }
976             else {
977 1         5 return 0;
978             }
979             }
980             else {
981 0         0 die("Can't handle $self->{ sig_hash }");
982             }
983              
984             } else {
985 0         0 return 0;
986             }
987             }
988              
989             ##
990             ## _get_node($xpath, context)
991             ##
992             ## Arguments:
993             ## $xpath: string XML XPath to use
994             ## $context: string XML context
995             ##
996             ## Returns: string XML NodeSet
997             ##
998             ## Return a NodeSet based on the xpath string
999             ##
1000             sub _get_node {
1001 706     706   1036 my $self = shift;
1002 706         1255 my ($xpath, $context) = @_;
1003 706         978 my $nodeset;
1004 706 100       1649 if ($context) {
1005 361         2384 $nodeset = $self->{parser}->find($xpath, $context);
1006             } else {
1007 345         1126 $nodeset = $self->{parser}->find($xpath);
1008             }
1009 706         44010 foreach my $node ($nodeset->get_nodelist) {
1010 706         5349 return $node;
1011             }
1012             }
1013              
1014             # TODO remove unused?
1015             sub _get_node_as_text {
1016 0     0   0 my $self = shift;
1017 0         0 my ($xpath, $context) = @_;
1018 0         0 my $node = $self->_get_node($xpath, $context);
1019 0 0       0 if ($node) {
1020 0         0 return $node->toString;
1021             } else {
1022 0         0 return '';
1023             }
1024             }
1025              
1026             # TODO remove unused?
1027             sub _transform_env_sig {
1028 0     0   0 my $self = shift;
1029 0         0 my ($str) = @_;
1030 0         0 my $prefix = '';
1031 0 0 0     0 if (defined $self->{dsig_prefix} && length $self->{dsig_prefix}) {
1032 0         0 $prefix = $self->{dsig_prefix} . ':';
1033             }
1034              
1035             # This removes the first Signature tag from the XML - even if there is another XML tree with another Signature inside and that comes first.
1036             # TODO: Remove the outermost Signature only.
1037              
1038 0         0 $str =~ s/(<${prefix}Signature(.*?)>(.*?)\<\/${prefix}Signature>)//is;
1039              
1040 0         0 return $str;
1041             }
1042              
1043             ##
1044             ## _trim($string)
1045             ##
1046             ## Arguments:
1047             ## $string: string String to remove whitespace
1048             ##
1049             ## Returns: string Trimmed String
1050             ##
1051             ## Trim the whitespace from the begining and end of the string
1052             ##
1053             sub _trim {
1054 1767     1767   87575 my $string = shift;
1055 1767         7457 $string =~ s/^\s+//;
1056 1767         11144 $string =~ s/\s+$//;
1057 1767         6435 return $string;
1058             }
1059              
1060             ##
1061             ## _load_ecdsa_key($key_text)
1062             ##
1063             ## Arguments:
1064             ## $key_text: string ECDSA Private Key as String
1065             ##
1066             ## Returns: nothing
1067             ##
1068             ## Populate:
1069             ## self->{KeyInfo}
1070             ## self->{key_obj}
1071             ## self->{key_type}
1072             ##
1073             sub _load_ecdsa_key {
1074 170     170   314 my $self = shift;
1075 170         331 my $key_text = shift;
1076              
1077 170 50       332 eval {require Crypt::PK::ECC; CryptX->VERSION('0.036'); 1}
  170         4525  
  170         64842  
  170         867  
1078             or confess "Crypt::PK::ECC 0.036+ needs to be installed so
1079             that we can handle ECDSA signatures";
1080              
1081 170         1205 my $ecdsa_key = Crypt::PK::ECC->new(\$key_text);
1082              
1083 170 50       1867609 if ( $ecdsa_key ) {
1084 170         487 $self->{ key_obj } = $ecdsa_key;
1085              
1086 170         10196 my $key_hash = $ecdsa_key->key2hash;
1087              
1088 170         469 my $oid = $key_hash->{ curve_oid };
1089 170         261 my $x = $key_hash->{ pub_x };
1090 170         292 my $y = $key_hash->{ pub_y };
1091              
1092 170         704 $self->{KeyInfo} = "
1093            
1094            
1095            
1096            
1097            
1098            
1099            
1100            
1101            
1102            
1103            
1104             ";
1105 170         1231 $self->{key_type} = 'ecdsa';
1106             }
1107             else {
1108 0         0 confess "did not get a new Crypt::PK::ECC object";
1109             }
1110             }
1111              
1112             ##
1113             ## _load_dsa_key($key_text)
1114             ##
1115             ## Arguments:
1116             ## $key_text: string DSA Private Key as String
1117             ##
1118             ## Returns: nothing
1119             ##
1120             ## Populate:
1121             ## self->{KeyInfo}
1122             ## self->{key_obj}
1123             ## self->{key_type}
1124             ##
1125             sub _load_dsa_key {
1126 56     56   98 my $self = shift;
1127 56         94 my $key_text = shift;
1128              
1129 56         101 eval {
1130 56         5814 require Crypt::OpenSSL::DSA;
1131             };
1132              
1133 56 50       21842 confess "Crypt::OpenSSL::DSA needs to be installed so that we can handle DSA keys." if $@;
1134              
1135 56         336 my $dsa_key = Crypt::OpenSSL::DSA->read_priv_key_str( $key_text );
1136              
1137 56 50       2636 if ( $dsa_key ) {
1138 56         143 $self->{ key_obj } = $dsa_key;
1139 56         450 my $g = encode_base64( $dsa_key->get_g(), '' );
1140 56         299 my $p = encode_base64( $dsa_key->get_p(), '' );
1141 56         243 my $q = encode_base64( $dsa_key->get_q(), '' );
1142 56         286 my $y = encode_base64( $dsa_key->get_pub_key(), '' );
1143              
1144 56         307 $self->{KeyInfo} = "
1145            
1146            
1147             $p
1148             $q
1149             $g
1150             $y
1151            
1152            
1153             ";
1154 56         153 $self->{key_type} = 'dsa';
1155             }
1156             else {
1157 0         0 confess "did not get a new Crypt::OpenSSL::RSA object";
1158             }
1159             }
1160              
1161             ##
1162             ## _load_rsa_key($key_text)
1163             ##
1164             ## Arguments:
1165             ## $key_text: string RSA Private Key as String
1166             ##
1167             ## Returns: nothing
1168             ##
1169             ## Populate:
1170             ## self->{KeyInfo}
1171             ## self->{key_obj}
1172             ## self->{key_type}
1173             ##
1174             sub _load_rsa_key {
1175 109     109   201 my $self = shift;
1176 109         271 my ($key_text) = @_;
1177              
1178 109         201 eval {
1179 109         6889 require Crypt::OpenSSL::RSA;
1180             };
1181 109 50       78060 confess "Crypt::OpenSSL::RSA needs to be installed so that we can handle RSA keys." if $@;
1182              
1183 109         5278 my $rsaKey = Crypt::OpenSSL::RSA->new_private_key( $key_text );
1184              
1185 109 50       492 if ( $rsaKey ) {
1186 109         419 $rsaKey->use_pkcs1_padding();
1187 109         237 $self->{ key_obj } = $rsaKey;
1188 109         228 $self->{ key_type } = 'rsa';
1189              
1190 109 100       339 if (!$self->{ x509 }) {
1191 55         1667 my $bigNum = ( $rsaKey->get_key_parameters() )[1];
1192 55         6974 my $bin = $bigNum->to_bin();
1193 55         259 my $exp = encode_base64( $bin, '' );
1194              
1195 55         1346 $bigNum = ( $rsaKey->get_key_parameters() )[0];
1196 55         1684 $bin = $bigNum->to_bin();
1197 55         235 my $mod = encode_base64( $bin, '' );
1198 55         344 $self->{KeyInfo} = "
1199            
1200            
1201             $mod
1202             $exp
1203            
1204            
1205             ";
1206             }
1207             }
1208             else {
1209 0         0 confess "did not get a new Crypt::OpenSSL::RSA object";
1210             }
1211             }
1212              
1213             ##
1214             ## _load_hmac_key_info()
1215             ##
1216             ## Arguments:
1217             ## none
1218             ##
1219             ## Returns: nothing
1220             ##
1221             ## Populate:
1222             ## self->{KeyInfo}
1223             ##
1224             sub _load_hmac_key_info {
1225 18     18   31 my $self = shift;
1226              
1227 18 50       64 if (! defined $self->{ key_name }) {
1228 0         0 return;
1229             }
1230              
1231 18         79 $self->{KeyInfo} = qq{$self->{key_name}};
1232             }
1233              
1234             ##
1235             ## _load_x509_key($key_text)
1236             ##
1237             ## Arguments:
1238             ## $key_text: string RSA Private Key as String
1239             ##
1240             ## Returns: nothing
1241             ##
1242             ## Populate:
1243             ## self->{key_obj}
1244             ## self->{key_type}
1245             ##
1246             sub _load_x509_key {
1247 0     0   0 my $self = shift;
1248 0         0 my $key_text = shift;
1249              
1250 0         0 eval {
1251 0         0 require Crypt::OpenSSL::X509;
1252             };
1253 0 0       0 confess "Crypt::OpenSSL::X509 needs to be installed so that we
1254             can handle X509 Certificates." if $@;
1255              
1256 0         0 my $x509Key = Crypt::OpenSSL::X509->new_private_key( $key_text );
1257              
1258 0 0       0 if ( $x509Key ) {
1259 0         0 $x509Key->use_pkcs1_padding();
1260 0         0 $self->{ key_obj } = $x509Key;
1261 0         0 $self->{key_type} = 'x509';
1262             }
1263             else {
1264 0         0 confess "did not get a new Crypt::OpenSSL::X509 object";
1265             }
1266             }
1267              
1268             ##
1269             ## _load_cert_file()
1270             ##
1271             ## Arguments: none
1272             ##
1273             ## Returns: nothing
1274             ##
1275             ## Read the file name from $self->{ cert } and
1276             ## Populate:
1277             ## self->{key_obj}
1278             ## $self->{KeyInfo}
1279             ##
1280             sub _load_cert_file {
1281 108     108   236 my $self = shift;
1282              
1283 108         179 eval {
1284 108         6648 require Crypt::OpenSSL::X509;
1285             };
1286              
1287 108 50       347888 confess "Crypt::OpenSSL::X509 needs to be installed so that we can handle X509 certs." if $@;
1288              
1289 108         239 my $file = $self->{ cert };
1290 108 50       4543 if ( open my $CERT, '<', $file ) {
1291 108         432 my $text = '';
1292 108         650 local $/ = undef;
1293 108         2739 $text = <$CERT>;
1294 108         1258 close $CERT;
1295              
1296 108         10295 my $cert = Crypt::OpenSSL::X509->new_from_string($text);
1297 108 50       615 if ( $cert ) {
1298 108         296 $self->{ cert_obj } = $cert;
1299 108         2382 my $cert_text = $cert->as_string;
1300 108         1379 $cert_text =~ s/-----[^-]*-----//gm;
1301 108         461 $self->{KeyInfo} = "\n"._trim($cert_text)."\n";
1302             }
1303             else {
1304 0         0 confess "Could not load certificate from $file";
1305             }
1306             }
1307             else {
1308 0         0 confess "Could not find certificate file $file";
1309             }
1310              
1311 108         519 return;
1312             }
1313              
1314             ##
1315             ## _load_cert_text()
1316             ##
1317             ## Arguments: none
1318             ##
1319             ## Returns: nothing
1320             ##
1321             ## Read the certificate from $self->{ cert_text } and
1322             ## Populate:
1323             ## self->{key_obj}
1324             ## $self->{KeyInfo}
1325             ##
1326             sub _load_cert_text {
1327 1     1   4 my $self = shift;
1328              
1329 1         2 eval {
1330 1         7 require Crypt::OpenSSL::X509;
1331             };
1332              
1333 1 50       5 confess "Crypt::OpenSSL::X509 needs to be installed so that we can handle X509 certs." if $@;
1334              
1335 1         3 my $text = $self->{ cert_text };
1336 1         138 my $cert = Crypt::OpenSSL::X509->new_from_string($text);
1337 1 50       6 if ( $cert ) {
1338 1         3 $self->{ cert_obj } = $cert;
1339 1         41 my $cert_text = $cert->as_string;
1340 1         14 $cert_text =~ s/-----[^-]*-----//gm;
1341 1         4 $self->{KeyInfo} = "\n"._trim($cert_text)."\n";
1342             }
1343             else {
1344 0         0 confess "Could not load certificate from given text.";
1345             }
1346              
1347 1         10 return;
1348             }
1349              
1350             ##
1351             ## _load_key($file)
1352             ##
1353             ## Arguments: $self->{ key }
1354             ##
1355             ## Returns: nothing
1356             ##
1357             ## Load the key and process it acording to its headers
1358             ##
1359             sub _load_key {
1360 337     337   527 my $self = shift;
1361 337         593 my $file = $self->{ key };
1362              
1363 337 100       16239 if ( open my $KEY, '<', $file ) {
1364 336         1200 my $text = '';
1365 336         1771 local $/ = undef;
1366 336         9727 $text = <$KEY>;
1367 336         4112 close $KEY;
1368              
1369 336 100       2723 if ( $text =~ m/BEGIN ([DR]SA) PRIVATE KEY/ ) {
    100          
    100          
    50          
1370 163         611 my $key_used = $1;
1371              
1372 163 100       437 if ( $key_used eq 'RSA' ) {
1373 107         384 $self->_load_rsa_key( $text );
1374             }
1375             else {
1376 56         221 $self->_load_dsa_key( $text );
1377             }
1378              
1379 163         1011 return 1;
1380             } elsif ( $text =~ m/BEGIN EC PRIVATE KEY/ ) {
1381 170         625 $self->_load_ecdsa_key( $text );
1382             } elsif ( $text =~ m/BEGIN PRIVATE KEY/ ) {
1383 2         10 $self->_load_rsa_key( $text );
1384             } elsif ($text =~ m/BEGIN CERTIFICATE/) {
1385 0         0 $self->_load_x509_key( $text );
1386             }
1387             else {
1388 1         16 confess "Could not detect type of key $file.";
1389             }
1390             }
1391             else {
1392 1         24 confess "Could not load key $file: $!";
1393             }
1394              
1395 172         748 return;
1396             }
1397              
1398             ##
1399             ## _signature_xml($signed_info,$signature_value)
1400             ##
1401             ## Arguments:
1402             ## $signed_info: string XML String Fragment
1403             ## $signature_value String Base64 Signature Value
1404             ##
1405             ## Returns: string XML fragment
1406             ##
1407             ## Create a XML string of the Signature
1408             ##
1409             sub _signature_xml {
1410 345     345   545 my $self = shift;
1411 345         691 my ($signed_info,$signature_value) = @_;
1412              
1413 345         2881 return qq{
1414             $signed_info
1415             $signature_value
1416             $self->{KeyInfo}
1417             };
1418             }
1419              
1420             ##
1421             ## _signedinfo_xml($digest_xml)
1422             ##
1423             ## Arguments:
1424             ## $digest_xml string XML String Fragment
1425             ##
1426             ## Returns: string XML fragment
1427             ##
1428             ## Create a XML string of the SignedInfo
1429             ##
1430             sub _signedinfo_xml {
1431 345     345   580 my $self = shift;
1432 345         607 my ($digest_xml) = @_;
1433              
1434 345         454 my $algorithm;
1435 345 50 33     1036 if (! defined $self->{key_type} && defined $self->{ hmac_key } ) {
1436 0         0 $self->{key_type} = 'hmac';
1437             }
1438              
1439 345 100 66     1587 if ( $self->{ sig_hash } eq 'sha1' && $self->{key_type} ne 'ecdsa' ) {
    100 66        
    100          
1440 30         104 $algorithm = "http://www.w3.org/2000/09/xmldsig#$self->{key_type}-$self->{ sig_hash }";
1441             }
1442             elsif ( $self->{key_type} eq 'ecdsa' ) {
1443 172 100 66     806 if ( $self->{ sig_hash } eq 'ripemd160' || $self->{ sig_hash } eq 'whirlpool' ) {
1444 12         38 $algorithm = "http://www.w3.org/2007/05/xmldsig-more#$self->{key_type}-$self->{ sig_hash }";
1445             }
1446             else {
1447 160         467 $algorithm = "http://www.w3.org/2001/04/xmldsig-more#$self->{key_type}-$self->{ sig_hash }";
1448             }
1449             }
1450             elsif ( $self->{ key_type } eq 'dsa' && $self->{ sig_hash } eq 'sha256') {
1451 28         77 $algorithm = "http://www.w3.org/2009/xmldsig11#$self->{key_type}-$self->{ sig_hash }";
1452             }
1453             else {
1454 115         301 $algorithm = "http://www.w3.org/2001/04/xmldsig-more#$self->{key_type}-$self->{ sig_hash }";
1455             }
1456              
1457             #return qq{
1458 345         1724 return qq{
1459            
1460            
1461             $digest_xml
1462             };
1463             }
1464              
1465             ##
1466             ## _reference_xml($id)
1467             ##
1468             ## Arguments:
1469             ## $id string XML ID related to the URI
1470             ## $digest string Base64 encoded digest
1471             ##
1472             ## Returns: string XML fragment
1473             ##
1474             ## Create a XML string of the Reference
1475             ##
1476             sub _reference_xml {
1477 345     345   646 my $self = shift;
1478 345         595 my $id = shift;
1479 345         692 my ($digest) = @_;
1480              
1481 345         571 my $algorithm;
1482 345 100 100     2055 if ( $self->{ digest_hash } eq 'sha1') {
    100          
1483 34         107 $algorithm = "http://www.w3.org/2000/09/xmldsig#$self->{ digest_hash }";
1484             }
1485             elsif (($self->{ digest_hash } eq 'sha224') || ($self->{ digest_hash } eq 'sha384')) {
1486 68         184 $algorithm = "http://www.w3.org/2001/04/xmldsig-more#$self->{ digest_hash }";
1487             }
1488             else {
1489 243         608 $algorithm = "http://www.w3.org/2001/04/xmlenc#$self->{ digest_hash }";
1490             }
1491              
1492 345         2225 return qq{
1493            
1494            
1495            
1496            
1497            
1498             $digest
1499             };
1500             }
1501              
1502              
1503             ##
1504             ## _canonicalize_xml($xml, $context)
1505             ##
1506             ## Arguments:
1507             ## $xml: string XML NodeSet
1508             ## $context: string XML Context
1509             ##
1510             ## Returns: string Canonical XML
1511             ##
1512             ## Canonicalizes xml based on the CanonicalizationMethod
1513             ## from the SignedInfo.
1514             ##
1515             sub _canonicalize_xml {
1516 712     712   1228 my $self = shift;
1517 712         1402 my ($xml, $context) = @_;
1518              
1519 712 50       1488 print ("_canonicalize_xml:\n") if $DEBUG;
1520             my $canon_method = $self->{ parser }->findnodes(
1521 712         2063 'dsig:SignedInfo/dsig:CanonicalizationMethod', $context
1522             );
1523              
1524 712         30393 foreach my $node ($canon_method->get_nodelist) {
1525 712         4522 my $alg = $node->getAttribute('Algorithm');
1526              
1527 712 50       8625 print (" Canon Method: $alg\n") if $DEBUG;
1528 712 100       3395 if ($alg eq TRANSFORM_C14N) {
    100          
    50          
    50          
    50          
    0          
1529 1 50       12 print (" toStringC14N\n") if $DEBUG;
1530 1         6 $xml = $xml->toStringC14N();
1531             }
1532             elsif ($alg eq TRANSFORM_C14N_COMMENTS) {
1533 4 50       58 print (" toStringC14N_Comments\n") if $DEBUG;
1534 4         34 $xml = $xml->toStringC14N(1);
1535             }
1536             elsif ($alg eq TRANSFORM_C14N_V1_1) {
1537 0 0       0 print (" toStringC14N_v1_1\n") if $DEBUG;
1538 0         0 $xml = $xml->toStringC14N_v1_1();
1539             }
1540             elsif ($alg eq TRANSFORM_C14N_V1_1_COMMENTS) {
1541 0 0       0 print (" toStringC14N_v1_1_Comments\n") if $DEBUG;
1542 0         0 $xml = $xml->toStringC14N_v1_1(1);
1543             }
1544             elsif ($alg eq TRANSFORM_EXC_C14N) {
1545 707 50       1284 print (" toStringEC14N\n") if $DEBUG;
1546 707         1802 $xml = $xml->toStringEC14N();
1547             }
1548             elsif ($alg eq TRANSFORM_EXC_C14N_COMMENTS) {
1549 0 0       0 print (" toStringEC14N_Comments\n") if $DEBUG;
1550 0         0 $xml = $xml->toStringEC14N(1);
1551             }
1552             else {
1553 0         0 die "Unsupported transform: $alg";
1554             }
1555             }
1556 712         116524 return $xml;
1557             }
1558              
1559             ##
1560             ## _calc_dsa_signature($signed_info_canon)
1561             ##
1562             ## Arguments:
1563             ## $canonical: string Canonical XML
1564             ##
1565             ## Returns: string Signature
1566             ##
1567             ## Calculates signature based on the method and hash
1568             ##
1569             sub _calc_dsa_signature {
1570 58     58   102 my $self = shift;
1571 58         104 my $signed_info_canon = shift;
1572              
1573 58 50       132 print (" Signing SignedInfo using DSA key type\n") if $DEBUG;
1574 58 50       370 if(my $ref = Digest::SHA->can($self->{ sig_hash })) {
    0          
1575 58         145 $self->{sig_method} = $ref;
1576             }
1577             elsif ( $ref = Crypt::Digest::RIPEMD160->can($self->{ sig_hash })) {
1578 0         0 $self->{sig_method} = $ref;
1579             }
1580             else {
1581 0         0 die("Can't handle $self->{ sig_hash }");
1582             }
1583              
1584             # DSA 1024-bit only permits the signing of 20 bytes or less, hence the sha1
1585             # DSA 2048-bit only permits the signing sha256
1586 58         53698 my $bin_signature = $self->{key_obj}->do_sign( $self->{ sig_method }($signed_info_canon) );
1587              
1588             # https://www.w3.org/TR/2002/REC-xmldsig-core-20020212/#sec-SignatureAlg
1589             # The output of the DSA algorithm consists of a pair of integers
1590             # The signature value consists of the base64 encoding of the
1591             # concatenation of r and s in that order ($r . $s)
1592 58         309 my $r = $bin_signature->get_r;
1593 58         179 my $s = $bin_signature->get_s;
1594              
1595 58         264 my $sig_size = ($self->{key_obj}->get_sig_size - 8) * 8;
1596 58         156 my $rs = _zero_fill_buffer($sig_size);
1597 58         192 _concat_dsa_sig_r_s(\$rs, $r, $s, $sig_size);
1598              
1599 58         445 return $rs;
1600              
1601             }
1602              
1603             ##
1604             ## _calc_ecdsa_signature($signed_info_canon)
1605             ##
1606             ## Arguments:
1607             ## $canonical: string Canonical XML
1608             ##
1609             ## Returns: string Signature
1610             ##
1611             ## Calculates signature based on the method and hash
1612             ##
1613             sub _calc_ecdsa_signature {
1614 172     172   312 my $self = shift;
1615 172         316 my $signed_info_canon = shift;
1616              
1617 172 50       423 print (" Signing SignedInfo using ECDSA key type\n") if $DEBUG;
1618              
1619             my $bin_signature = $self->{key_obj}->sign_message_rfc7518(
1620             $signed_info_canon, uc($self->{sig_hash})
1621 172         963711 );
1622             # The output of the ECDSA algorithm consists of a pair of integers
1623             # The signature value consists of the base64 encoding of the
1624             # concatenation of r and s in that order ($r . $s). In this
1625             # case sign_message_rfc7518 produces that
1626 172         1427 return $bin_signature;
1627             }
1628              
1629             ##
1630             ## _calc_rsa_signature($signed_info_canon)
1631             ##
1632             ## Arguments:
1633             ## $canonical: string Canonical XML
1634             ##
1635             ## Returns: string Signature
1636             ##
1637             ## Calculates signature based on the method and hash
1638             ##
1639             sub _calc_rsa_signature {
1640 109     109   177 my $self = shift;
1641 109         170 my $signed_info_canon = shift;
1642              
1643 109 50       249 print (" Signing SignedInfo using RSA key type\n") if $DEBUG;
1644 109         286 my $sig_hash = 'use_' . $self->{ sig_hash } . '_hash';
1645 109         536 $self->{key_obj}->$sig_hash;
1646 109         287996 my $bin_signature = $self->{key_obj}->sign( $signed_info_canon );
1647              
1648 109         891 return $bin_signature;
1649             }
1650              
1651             ##
1652             ## _calc_hmac_signature($signed_info_canon)
1653             ##
1654             ## Arguments:
1655             ## $signed_info_canon: string Canonical XML
1656             ##
1657             ## Returns: string Signature
1658             ##
1659             ## Calculates signature based on the method and hash
1660             ##
1661             sub _calc_hmac_signature {
1662 18     18   38 my $self = shift;
1663 18         37 my $signed_info_canon = shift;
1664              
1665 23     23   219 use Crypt::Mac::HMAC qw( hmac );
  23         77  
  23         6353  
1666 18         24 my $bin_signature;
1667 18 50       40 print (" Signing SignedInfo using hmac-", $self->{ sig_hash }, "\n") if $DEBUG;
1668 18 100       151 if (my $ref = Digest::SHA->can('hmac_' . $self->{ sig_hash })) {
    50          
1669 15         35 $self->{sig_method} = $ref;
1670             $bin_signature = $self->{sig_method} (
1671             $signed_info_canon,
1672             decode_base64( $self->{ hmac_key } )
1673 15         369 );
1674             }
1675             elsif ( $ref = Crypt::Digest::RIPEMD160->can($self->{ sig_hash })) {
1676 3         8 $self->{sig_method} = $ref;
1677 3         96 $bin_signature = hmac('RIPEMD160', decode_base64( $self->{ hmac_key } ), $signed_info_canon );
1678             }
1679             else {
1680 0         0 die("Can't handle $self->{ sig_hash }");
1681             }
1682              
1683 18         76 return $bin_signature;
1684             }
1685             1;
1686              
1687             =pod
1688              
1689             =encoding UTF-8
1690              
1691             =head1 NAME
1692              
1693             XML::Sig - XML::Sig - A toolkit to help sign and verify XML Digital Signatures
1694              
1695             =head1 VERSION
1696              
1697             version 0.62
1698              
1699             =head1 SYNOPSIS
1700              
1701             my $xml = '123';
1702             my $signer = XML::Sig->new({
1703             key => 'path/to/private.key',
1704             });
1705              
1706             # create a signature
1707             my $signed = $signer->sign($xml);
1708             print "Signed XML: $signed\n";
1709              
1710             # verify a signature
1711             $signer->verify($signed)
1712             or die "Signature Invalid.";
1713             print "Signature valid.\n";
1714              
1715             =head1 DESCRIPTION
1716              
1717             This perl module provides two primary capabilities: given an XML string, create
1718             and insert digital signatures, or if one is already present in the string verify
1719             it -- all in accordance with the W3C standard governing XML signatures.
1720              
1721             =head1 NAME
1722              
1723             XML::Sig - A toolkit to help sign and verify XML Digital Signatures.
1724              
1725             =head1 PREREQUISITES
1726              
1727             =over
1728              
1729             =item * L
1730              
1731             =item * L
1732              
1733             =item * L
1734              
1735             =item * L
1736              
1737             =item * L
1738              
1739             =item * L
1740              
1741             =item * L
1742              
1743             =item * L
1744              
1745             =back
1746              
1747             =head1 USAGE
1748              
1749             =head2 SUPPORTED ALGORITHMS & TRANSFORMS
1750              
1751             This module supports the following signature methods:
1752              
1753             =over
1754              
1755             =item * DSA
1756              
1757             =item * RSA
1758              
1759             =item * RSA encoded as x509
1760              
1761             =item * ECDSA
1762              
1763             =item * ECDSA encoded as x509
1764              
1765             =item * HMAC
1766              
1767             =back
1768              
1769             This module supports the following canonicalization methods and transforms:
1770              
1771             =over
1772              
1773             =item * Enveloped Signature
1774              
1775             =item * REC-xml-c14n-20010315#
1776              
1777             =item * REC-xml-c14n-20010315#WithComments
1778              
1779             =item * REC-xml-c14n11-20080502
1780              
1781             =item * REC-xml-c14n11-20080502#WithComments
1782              
1783             =item * xml-exc-c14n#
1784              
1785             =item * xml-exc-c14n#WithComments
1786              
1787             =back
1788              
1789             =head2 OPTIONS
1790              
1791             Each of the following options are also accessors on the main
1792             XML::Sig object. TODO Not strictly correct rewrite
1793              
1794             =over
1795              
1796             =item B
1797              
1798             The path to a file containing the contents of a private key. This option
1799             is used only when generating signatures.
1800              
1801             =item B
1802              
1803             The path to a file containing a PEM-formatted X509 certificate. This
1804             option is used only when generating signatures with the "x509"
1805             option. This certificate will be embedded in the signed document, and
1806             should match the private key used for the signature.
1807              
1808             =item B
1809              
1810             A string containing a PEM-formatted X509 certificate. This
1811             option is used only when generating signatures with the "x509"
1812             option. This certificate will be embedded in the signed document, and
1813             should match the private key used for the signature.
1814              
1815             =item B
1816              
1817             Takes a true (1) or false (0) value and indicates how you want the
1818             signature to be encoded. When true, the X509 certificate supplied will
1819             be encoded in the signature. Otherwise the native encoding format for
1820             RSA, DSA and ECDSA will be used.
1821              
1822             =item B
1823              
1824             Passing sig_hash to new allows you to specify the SignatureMethod
1825             hashing algorithm used when signing the SignedInfo. RSA and ECDSA
1826             supports the hashes specified sha1, sha224, sha256, sha384 and sha512
1827              
1828             DSA supports only sha1 and sha256 (but you really should not sign
1829             anything with DSA anyway). This is over-ridden by the key's signature
1830             size which is related to the key size. 1024-bit keys require sha1,
1831             2048-bit and 3072-bit keys require sha256.
1832              
1833             =item B
1834              
1835             Passing digest_hash to new allows you to specify the DigestMethod
1836             hashing algorithm used when calculating the hash of the XML being
1837             signed. Supported hashes can be specified sha1, sha224, sha256,
1838             sha384, sha512, ripemd160
1839              
1840             =item B
1841              
1842             Base64 encoded hmac_key
1843              
1844             =item B
1845              
1846             The name of the key that should be referenced. In the case of
1847             xmlsec the --keys-file (ex. t/xmlsec-keys.xml) holds keys with a
1848             KeyName that is referenced by this name.
1849              
1850             =item B
1851              
1852             Some applications such as Net::SAML2 expect to sign a fragment of the
1853             full XML document so is this is true (1) it will not include the
1854             XML Declaration at the beginning of the signed XML. False (0) or
1855             undefined returns an XML document starting with the XML Declaration.
1856              
1857             =back
1858              
1859             The following options act similar to C<< xmlsec --id-attr:ID
1860             : >>
1861              
1862             =over
1863              
1864             =item B
1865              
1866             A HashRef to namespaces you want to define to select the correct attribute ID on
1867              
1868             =item B
1869              
1870             The xpath string you want to sign your XML message on.
1871              
1872             =back
1873              
1874             =head2 METHODS
1875              
1876             =head3 B
1877              
1878             Constructor; see OPTIONS above.
1879              
1880             =head3 B
1881              
1882             When given a string of XML, it will return the same string with a signature
1883             generated from the key provided when the XML::Sig object was initialized.
1884              
1885             This method will sign all elements in your XML with an ID (case sensitive)
1886             attribute. Each element with an ID attribute will be the basis for a seperate
1887             signature. It will correspond to the URI attribute in the Reference element
1888             that will be contained by the signature. If no ID attribute can be found on
1889             an element, the signature will not be created.
1890              
1891             The elements are signed in reverse order currently assuming (possibly
1892             incorrectly) that the lower element in the tree may need to be signed
1893             inclusive of its Signature because it is a child of the higher element.
1894              
1895             Arguments:
1896             $xml: string XML string
1897              
1898             Returns: string Signed XML
1899              
1900             =head3 B
1901              
1902             Returns true or false based upon whether the signature is valid or not.
1903              
1904             When using XML::Sig exclusively to verify a signature, no key needs to be
1905             specified during initialization given that the public key should be
1906             transmitted with the signature.
1907              
1908             XML::Sig checks all signature in the provided xml and will fail should any
1909             signature pointing to an existing ID in the XML fail to verify.
1910              
1911             Should there be a Signature included that does not point to an existing node
1912             in the XML it is ignored and other Signaures are checked. If there are no
1913             other Signatures it will return false.
1914              
1915             Arguments:
1916             $xml: string XML string
1917              
1918             Returns: string Signed XML
1919              
1920             =head3 B
1921              
1922             Following a successful verify with an X509 certificate, returns the
1923             signer's certificate as embedded in the XML document for verification
1924             against a CA certificate. The certificate is returned as a
1925             Crypt::OpenSSL::X509 object.
1926              
1927             Arguments: none
1928              
1929             Returns: Crypt::OpenSSL::X509: Certificate used to sign the XML
1930              
1931             =head1 ABOUT DIGITAL SIGNATURES
1932              
1933             Just as one might want to send an email message that is cryptographically signed
1934             in order to give the recipient the means to independently verify who sent the email,
1935             one might also want to sign an XML document. This is especially true in the
1936             scenario where an XML document is received in an otherwise unauthenticated
1937             context, e.g. SAML.
1938              
1939             However XML provides a challenge that email does not. In XML, two documents can be
1940             byte-wise inequivalent, and semanticaly equivalent at the same time. For example:
1941              
1942            
1943            
1944            
1945            
1946              
1947             And:
1948              
1949            
1950            
1951            
1952            
1953              
1954             Each of these document express the same thing, or in other words they "mean"
1955             the same thing. However if you were to strictly sign the raw text of these
1956             documents, they would each produce different signatures.
1957              
1958             XML Signatures on the other hand will produce the same signature for each of
1959             the documents above. Therefore an XML document can be written and rewritten by
1960             different parties and still be able to have someone at the end of the line
1961             verify a signature the document may contain.
1962              
1963             There is a specially subscribed methodology for how this process should be
1964             executed and involves transforming the XML into its canonical form so a
1965             signature can be reliably inserted or extracted for verification. This
1966             module implements that process.
1967              
1968             =head2 EXAMPLE SIGNATURE
1969              
1970             Below is a sample XML signature to give you some sense of what they look like.
1971             First let's look at the original XML document, prior to being signed:
1972              
1973            
1974            
1975             123
1976            
1977              
1978             Now, let's insert a signature:
1979              
1980            
1981            
1982             123
1983            
1984            
1985            
1986            
1987            
1988            
1989            
1990            
1991            
1992             9kpmrvv3peVJpNSTRycrV+jeHVY=
1993            
1994            
1995            
1996             HXUBnMgPJf//j4ihaWnaylNwAR5AzDFY83HljFIlLmTqX1w1C72ZTuRObvYve8TNEbVsQlTQkj4R
1997             hiY0pgIMQUb75GLYFtc+f0YmBZf5rCWY3NWzo432D3ogAvpEzYXEQPmicWe2QozQhybaz9/wrYki
1998             XiXY+57fqCkf7aT8Bb6G+fn7Aj8gnZFLkmKxwCdyGsIZOIZdQ8MWpeQrifxBR0d8W1Zm6ix21WNv
1999             ONt575h7VxLKw8BDhNPS0p8CS3hOnSk29stpiDMCHFPxAwrbKVL1kGDLaLZn1q8nNRmH8oFxG15l
2000             UmS3JXDZAss8gZhU7g9T4XllCqjrAvzPLOFdeQ==
2001            
2002            
2003            
2004            
2005            
2006             1b+m37u3Xyawh2ArV8txLei251p03CXbkVuWaJu9C8eHy1pu87bcthi+T5WdlCPKD7KGtkKn9vq
2007             i4BJBZcG/Y10e8KWVlXDLg9gibN5hb0Agae3i1cCJTqqnQ0Ka8w1XABtbxTimS1B0aO1zYW6d+U
2008             Yl0xIeAOPsGMfWeu1NgLChZQton1/NrJsKwzMaQy1VI8m4gUleit9Z8mbz9bNMshdgYEZ9oC4bH
2009             n/SnA4FvQl1fjWyTpzL/aWF/bEzS6Qd8IBk7yhcWRJAGdXTWtwiX4mXb4h/2sdrSNvyOsd/shCf
2010             OSMsf0TX+OdlbH079AsxOwoUjlzjuKdCiFPdU6yAJw==
2011            
2012             Iw==
2013            
2014            
2015            
2016            
2017            
2018              
2019             =head1 SEE ALSO
2020              
2021             L
2022              
2023             =head1 VERSION CONTROL
2024              
2025             L
2026              
2027             =head1 AUTHORS and CREDITS
2028              
2029             Author: Byrne Reese
2030              
2031             Thanks to Manni Heumann who wrote Google::SAML::Response from
2032             which this module borrows heavily in order to create digital
2033             signatures.
2034              
2035             Net::SAML2 embedded version amended by Chris Andrews .
2036              
2037             Maintainer: Timothy Legge
2038              
2039             =head1 AUTHORS
2040              
2041             =over 4
2042              
2043             =item *
2044              
2045             Byrne Reese
2046              
2047             =item *
2048              
2049             Timothy Legge
2050              
2051             =back
2052              
2053             =head1 COPYRIGHT AND LICENSE
2054              
2055             This software is copyright (c) 2023 by Byrne Reese, Chris Andrews and Others; in detail:
2056              
2057             Copyright 2009 Byrne, Michael Hendricks
2058             2010 Chris Andrews
2059             2011 Chris Andrews, Oskari Okko Ojala
2060             2012 Chris Andrews, Peter Marschall
2061             2015 Mike Wisener
2062             2016 Jeff Fearn
2063             2017 Mike Wisener, xmikew
2064             2019-2021 Timothy Legge
2065             2022 Timothy Legge, Wesley Schwengle
2066             2023 Timothy Legge
2067              
2068              
2069             This is free software; you can redistribute it and/or modify it under
2070             the same terms as the Perl 5 programming language system itself.
2071              
2072             =cut
2073              
2074             __END__