File Coverage

blib/lib/Data/Validate/DNS/TLSA.pm
Criterion Covered Total %
statement 96 98 97.9
branch 46 54 85.1
condition 38 51 74.5
subroutine 16 16 100.0
pod 8 8 100.0
total 204 227 89.8


line stmt bran cond sub pod time code
1             #
2             # This file is part of Data-Validate-DNS-TLSA
3             #
4             # This software is copyright (c) 2018 by Michael Schout.
5             #
6             # This is free software; you can redistribute it and/or modify it under
7             # the same terms as the Perl 5 programming language system itself.
8             #
9              
10             package Data::Validate::DNS::TLSA;
11             $Data::Validate::DNS::TLSA::VERSION = '0.02';
12             # ABSTRACT: Validate DNS Transport Layer Security Association (TLSA) Record Values
13              
14 3     3   154499 use strict;
  3         26  
  3         68  
15 3     3   15 use warnings;
  3         6  
  3         80  
16              
17 3     3   431 use parent 'Exporter';
  3         293  
  3         12  
18              
19 3     3   472 use List::Util qw(any);
  3         5  
  3         254  
20 3     3   735 use Taint::Util qw(untaint);
  3         652  
  3         13  
21              
22             our @EXPORT_OK = qw(
23             is_tlsa_port
24             is_tlsa_protocol
25             is_tlsa_domain_name
26             is_tlsa_selector
27             is_tlsa_matching_type
28             is_tlsa_cert_usage
29             is_tlsa_cert_association);
30              
31             our %EXPORT_TAGS = (
32             all => \@EXPORT_OK);
33              
34              
35             sub new {
36 2     2 1 314 my $class = shift;
37 2   33     14 bless { @_ }, ref $class || $class;
38             }
39              
40              
41             sub is_tlsa_port {
42 13     13 1 1616 my ($self, $value, %opts) = _maybe_oo(@_);
43              
44 13   100     47 $opts{underscore} ||= 0;
45              
46 13 100 100     48 if ($opts{underscore} and substr($value,0,1) ne '_') {
47 2         6 return;
48             }
49              
50 11         43 (my $port = $value) =~ s/^_//;
51              
52 11 100       57 unless ($port =~ /^[1-9][0-9]*$/) {
53 2         9 return;
54             }
55              
56 9 100 66     45 if ($port < 0 or $port > 65535) {
57 1         3 return;
58             }
59              
60 8         22 untaint($value);
61              
62 8         38 return $value;
63             }
64              
65              
66             sub is_tlsa_protocol {
67 15     15 1 1685 my ($self, $value, %opts) = _maybe_oo(@_);
68              
69 15   100     56 $opts{underscore} ||= 0;
70 15   100     53 $opts{strict} ||= 0;
71              
72 15 100 100     57 if ($opts{underscore} and substr($value,0,1) ne '_') {
73 2         6 return;
74             }
75              
76 13         53 (my $proto = $value) =~ s/^_//;
77              
78 13 100       50 unless ($proto =~ /^[a-zA-Z]+$/) {
79 1         6 return;
80             }
81              
82 12 100       28 if ($opts{strict}) {
83             # strict mode, only allow protocols specified in RFC 6698
84 4 100   9   15 unless (any { $_ eq lc($proto) } qw(tcp udp sctp)) {
  9         16  
85 1         4 return;
86             }
87             }
88              
89             # otherwise, we already checked that its a-Z.
90 11         26 untaint($value);
91              
92 11         47 return $value;
93             }
94              
95              
96             sub is_tlsa_domain_name {
97 6     6 1 1028 my ($self, $value, %opts) = _maybe_oo(@_);
98              
99 6 50       20 unless (defined $opts{underscore}) {
100 6         12 $opts{underscore} = 1;
101             }
102              
103 6         20 my @labels = split /\./, $value;
104              
105 6 100       15 if (scalar @labels < 2) {
106 1         6 return;
107             }
108              
109 5         14 my ($port, $proto) = @labels;
110              
111 5 100 100     16 if (is_tlsa_port($port, %opts) and is_tlsa_protocol($proto, %opts)) {
112 3         11 untaint($value);
113 3         13 return $value;
114             }
115              
116 2         8 return;
117             }
118              
119              
120             sub is_tlsa_matching_type {
121 516     516 1 50467 my ($self, $value, %opts) = _maybe_oo(@_);
122              
123 516 100       773 return unless _is_int8($value);
124              
125 514 100       808 if ($opts{strict}) {
126             # strict mode, only allow registered types
127 256 100 66     767 if (($value >= 0 and $value < 3) or $value == 255) {
      100        
128 4         9 untaint($value);
129 4         14 return $value;
130             }
131             }
132             else {
133             # just a syntax check
134 258 50 33     603 if ($value >= 0 and $value <= 255) {
135 258         458 untaint($value);
136 258         489 return $value;
137             }
138             }
139              
140 252         516 return;
141             }
142              
143              
144             sub is_tlsa_selector {
145 511     511 1 50328 my ($self, $value, %opts) = _maybe_oo(@_);
146              
147 511 50       734 return unless _is_int8($value);
148              
149 511 100       762 if ($opts{strict}) {
150             # strict mode, only allow registered selectors
151 256 100 66     743 if (($value >= 0 and $value < 2) or $value == 255) {
      100        
152 3         7 untaint($value);
153 3         11 return $value;
154             }
155             }
156             else {
157             # just a syntax check
158 255 50 33     591 if ($value >= 0 and $value <= 255) {
159 255         439 untaint($value);
160 255         495 return $value;
161             }
162             }
163              
164 253         462 return;
165             }
166              
167              
168             sub is_tlsa_cert_usage {
169 514     514 1 52080 my ($self, $value, %opts) = _maybe_oo(@_);
170              
171 514 50       792 return unless _is_int8($value);
172              
173 514 100       783 if ($opts{strict}) {
174             # strict mode, only allow registered values
175 256 100 66     788 if (($value >= 0 and $value < 4) or $value == 255) {
      100        
176 5         11 untaint($value);
177 5         17 return $value;
178             }
179             }
180             else {
181             # just a syntax check
182 258 50 33     592 if ($value >= 0 and $value <= 255) {
183 258         433 untaint($value);
184 258         667 return $value;
185             }
186             }
187              
188 251         673 return;
189             }
190              
191              
192             sub is_tlsa_cert_association {
193 6     6 1 1198 my ($self, $value) = _maybe_oo(@_);
194              
195             # must contain some hex chars
196 6 100       27 if ($value !~ /[0-9a-fA-F]/) {
197 2         7 return;
198             }
199              
200             # hex string with white space allowed.
201 4 50       25 if ($value =~ /[^0-9a-fA-F\s]/) {
202 0         0 return;
203             }
204              
205 4         17 untaint($value);
206              
207 4         12 return $value;
208             }
209              
210             sub _is_int8 {
211 1541     1541   1879 my $val = shift;
212              
213 1541 50       3592 if ($val =~ /[^0-9]/) {
214 0         0 return 0;
215             }
216              
217 1541 100 66     3938 if ($val < 0 or $val > 255) {
218 2         8 return 0;
219             }
220             else {
221 1539         2654 return 1;
222             }
223             }
224              
225             sub _maybe_oo {
226 1581 100   1581   2834 my $self = shift if ref $_[0];
227              
228 1581         3103 return ($self, @_);
229             }
230              
231             1;
232              
233             __END__