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.01';
12             # ABSTRACT: Validate DNS Transport Layer Security Association (TLSA) Record Values
13              
14 3     3   177060 use strict;
  3         20  
  3         68  
15 3     3   13 use warnings;
  3         4  
  3         66  
16              
17 3     3   408 use parent 'Exporter';
  3         248  
  3         11  
18              
19 3     3   140 use List::Util qw(any);
  3         5  
  3         252  
20 3     3   810 use Taint::Util qw(untaint);
  3         744  
  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 237 my $class = shift;
37 2   33     14 bless { @_ }, ref $class || $class;
38             }
39              
40              
41             sub is_tlsa_port {
42 13     13 1 1724 my ($self, $value, %opts) = _maybe_oo(@_);
43              
44 13   100     48 $opts{underscore} ||= 0;
45              
46 13 100 100     55 if ($opts{underscore} and substr($value,0,1) ne '_') {
47 2         7 return;
48             }
49              
50 11         43 (my $port = $value) =~ s/^_//;
51              
52 11 100       48 unless ($port =~ /^[1-9][0-9]*$/) {
53 2         7 return;
54             }
55              
56 9 100 66     40 if ($port < 0 or $port > 65535) {
57 1         4 return;
58             }
59              
60 8         24 untaint($value);
61              
62 8         69 return $value;
63             }
64              
65              
66             sub is_tlsa_protocol {
67 15     15 1 1917 my ($self, $value, %opts) = _maybe_oo(@_);
68              
69 15   100     51 $opts{underscore} ||= 0;
70 15   100     57 $opts{strict} ||= 0;
71              
72 15 100 100     50 if ($opts{underscore} and substr($value,0,1) ne '_') {
73 2         7 return;
74             }
75              
76 13         81 (my $proto = $value) =~ s/^_//;
77              
78 13 100       53 unless ($proto =~ /^[a-zA-Z]+$/) {
79 1         6 return;
80             }
81              
82 12 100       24 if ($opts{strict}) {
83             # strict mode, only allow protocols specified in RFC 6698
84 4 100   9   35 unless (any { $_ eq lc($proto) } qw(tcp udp sctp)) {
  9         15  
85 1         5 return;
86             }
87             }
88              
89             # otherwise, we already checked that its a-Z.
90 11         32 untaint($value);
91              
92 11         39 return $value;
93             }
94              
95              
96             sub is_tlsa_domain_name {
97 6     6 1 1113 my ($self, $value, %opts) = _maybe_oo(@_);
98              
99 6 50       19 unless (defined $opts{underscore}) {
100 6         11 $opts{underscore} = 1;
101             }
102              
103 6         19 my @labels = split /\./, $value;
104              
105 6 100       18 if (scalar @labels < 2) {
106 1         9 return;
107             }
108              
109 5         11 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         20 return $value;
114             }
115              
116 2         18 return;
117             }
118              
119              
120             sub is_tlsa_matching_type {
121 516     516 1 59379 my ($self, $value, %opts) = _maybe_oo(@_);
122              
123 516 100       805 return unless _is_int8($value);
124              
125 514 100       908 if ($opts{strict}) {
126             # strict mode, only allow registered types
127 256 100 66     892 if (($value >= 0 and $value < 3) or $value == 255) {
      100        
128 4         9 untaint($value);
129 4         17 return $value;
130             }
131             }
132             else {
133             # just a syntax check
134 258 50 33     682 if ($value >= 0 and $value <= 255) {
135 258         517 untaint($value);
136 258         607 return $value;
137             }
138             }
139              
140 252         640 return;
141             }
142              
143              
144             sub is_tlsa_selector {
145 511     511 1 61078 my ($self, $value, %opts) = _maybe_oo(@_);
146              
147 511 50       862 return unless _is_int8($value);
148              
149 511 100       885 if ($opts{strict}) {
150             # strict mode, only allow registered selectors
151 256 100 66     926 if (($value >= 0 and $value < 2) or $value == 255) {
      100        
152 3         8 untaint($value);
153 3         11 return $value;
154             }
155             }
156             else {
157             # just a syntax check
158 255 50 33     734 if ($value >= 0 and $value <= 255) {
159 255         520 untaint($value);
160 255         656 return $value;
161             }
162             }
163              
164 253         585 return;
165             }
166              
167              
168             sub is_tlsa_cert_usage {
169 514     514 1 62268 my ($self, $value, %opts) = _maybe_oo(@_);
170              
171 514 50       918 return unless _is_int8($value);
172              
173 514 100       893 if ($opts{strict}) {
174             # strict mode, only allow registered values
175 256 100 66     919 if (($value >= 0 and $value < 4) or $value == 255) {
      100        
176 5         11 untaint($value);
177 5         20 return $value;
178             }
179             }
180             else {
181             # just a syntax check
182 258 50 33     694 if ($value >= 0 and $value <= 255) {
183 258         569 untaint($value);
184 258         824 return $value;
185             }
186             }
187              
188 251         800 return;
189             }
190              
191              
192             sub is_tlsa_cert_association {
193 6     6 1 1403 my ($self, $value) = _maybe_oo(@_);
194              
195             # must contain some hex chars
196 6 100       29 if ($value !~ /[0-9a-fA-F]/) {
197 2         9 return;
198             }
199              
200             # hex string with white space allowed.
201 4 50       13 if ($value =~ /[^0-9a-fA-F\s]/) {
202 0         0 return;
203             }
204              
205 4         14 untaint($value);
206              
207 4         22 return $value;
208             }
209              
210             sub _is_int8 {
211 1541     1541   2112 my $val = shift;
212              
213 1541 50       4251 if ($val =~ /[^0-9]/) {
214 0         0 return 0;
215             }
216              
217 1541 100 66     4955 if ($val < 0 or $val > 255) {
218 2         21 return 0;
219             }
220             else {
221 1539         3253 return 1;
222             }
223             }
224              
225             sub _maybe_oo {
226 1581 100   1581   3253 my $self = shift if ref $_[0];
227              
228 1581         3683 return ($self, @_);
229             }
230              
231             1;
232              
233             __END__