1package Net::DNS::SEC::DSA;
2
3use strict;
4use warnings;
5
6our $VERSION = (qw$Id: DSA.pm 1853 2021-10-11 10:40:59Z willem $)[2];
7
8
9=head1 NAME
10
11Net::DNS::SEC::DSA - DNSSEC DSA digital signature algorithm
12
13
14=head1 SYNOPSIS
15
16    require Net::DNS::SEC::DSA;
17
18    $signature = Net::DNS::SEC::DSA->sign( $sigdata, $private );
19
20    $validated = Net::DNS::SEC::DSA->verify( $sigdata, $keyrr, $sigbin );
21
22
23=head1 DESCRIPTION
24
25Implementation of DSA digital signature
26generation and verification procedures.
27
28=head2 sign
29
30    $signature = Net::DNS::SEC::DSA->sign( $sigdata, $private );
31
32Generates the wire-format signature from the sigdata octet string
33and the appropriate private key object.
34
35=head2 verify
36
37    $validated = Net::DNS::SEC::DSA->verify( $sigdata, $keyrr, $sigbin );
38
39Verifies the signature over the sigdata octet string using the specified
40public key resource record.
41
42=cut
43
44use integer;
45use MIME::Base64;
46
47use constant DSA_configured => Net::DNS::SEC::libcrypto->can('EVP_PKEY_new_DSA');
48
49BEGIN { die 'DSA disabled or application has no "use Net::DNS::SEC"' unless DSA_configured }
50
51
52my %parameters = (
53	3 => Net::DNS::SEC::libcrypto::EVP_sha1(),
54	6 => Net::DNS::SEC::libcrypto::EVP_sha1(),
55	);
56
57sub _index { return keys %parameters }
58
59
60sub sign {
61	my ( $class, $sigdata, $private ) = @_;
62
63	my $index = $private->algorithm;
64	my $evpmd = $parameters{$index} || die 'private key not DSA';
65
66	my ( $p, $q, $g, $x, $y ) =
67			map { decode_base64( $private->$_ ) } qw(prime subprime base private_value public_value);
68	my $t = ( length($g) - 64 ) / 8;
69
70	my $evpkey = Net::DNS::SEC::libcrypto::EVP_PKEY_new_DSA( $p, $q, $g, $y, $x );
71
72	my $asn1 = Net::DNS::SEC::libcrypto::EVP_sign( $sigdata, $evpkey, $evpmd );
73	return _ASN1decode( $asn1, $t );
74}
75
76
77sub verify {
78	my ( $class, $sigdata, $keyrr, $sigbin ) = @_;
79
80	my $index = $keyrr->algorithm;
81	my $evpmd = $parameters{$index} || die 'public key not DSA';
82
83	return unless $sigbin;
84
85	my $key = $keyrr->keybin;				# public key
86	my $len = 64 + 8 * unpack( 'C', $key );			# RFC2536, section 2
87	my ( $q, $p, $g, $y ) = unpack "x a20 a$len a$len a$len", $key;
88
89	my $evpkey = Net::DNS::SEC::libcrypto::EVP_PKEY_new_DSA( $p, $q, $g, $y, '' );
90
91	my $asn1 = _ASN1encode($sigbin);
92	return Net::DNS::SEC::libcrypto::EVP_verify( $sigdata, $asn1, $evpkey, $evpmd );
93}
94
95
96########################################
97
98sub _ASN1encode {
99	my @part = unpack 'x a20 a20', shift;			# discard "t"
100	my $length;
101	foreach (@part) {
102		s/^[\000]+//;
103		s/^$/\000/;
104		s/^(?=[\200-\377])/\000/;
105		$_ = pack 'C2 a*', 2, length, $_;
106		$length += length;
107	}
108	return pack 'C2 a* a*', 0x30, $length, @part;
109}
110
111sub _ASN1decode {
112	my ( $asn1, $t ) = @_;
113	my $n	 = unpack 'x3 C',	   $asn1;
114	my $m	 = unpack "x5 x$n C",	   $asn1;
115	my @part = unpack "x4 a$n x2 a$m", $asn1;
116	return pack 'C a* a*', $t, map { substr( pack( 'x20 a*', $_ ), -20 ) } @part;
117}
118
119
1201;
121
122__END__
123
124########################################
125
126=head1 ACKNOWLEDGMENT
127
128Thanks are due to Eric Young and the many developers and
129contributors to the OpenSSL cryptographic library.
130
131
132=head1 COPYRIGHT
133
134Copyright (c)2014,2018 Dick Franks.
135
136All rights reserved.
137
138
139=head1 LICENSE
140
141Permission to use, copy, modify, and distribute this software and its
142documentation for any purpose and without fee is hereby granted, provided
143that the original copyright notices appear in all copies and that both
144copyright notice and this permission notice appear in supporting
145documentation, and that the name of the author not be used in advertising
146or publicity pertaining to distribution of the software without specific
147prior written permission.
148
149THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
150IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
151FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
152THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
153LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
154FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
155DEALINGS IN THE SOFTWARE.
156
157
158=head1 SEE ALSO
159
160L<Net::DNS>, L<Net::DNS::SEC>,
161RFC2536,
162L<OpenSSL|http://www.openssl.org/docs>
163
164=cut
165
166