File Coverage

blib/lib/Unix/Conf/Bind8/Conf/Trustedkeys.pm
Criterion Covered Total %
statement 30 129 23.2
branch 0 70 0.0
condition 0 23 0.0
subroutine 10 20 50.0
pod 7 7 100.0
total 47 249 18.8


line stmt bran cond sub pod time code
1             # Bind8 trusted-keys handling
2             #
3             # Copyright Karthik Krishnamurthy
4              
5             =head1 NAME
6              
7             Unix::Conf::Bind8::Conf::Trustedkeys - Class for handling Bind8 configuration
8             directive `trustedkeys'.
9              
10             =head1 SYNOPSIS
11              
12             use Unix::Conf::Bind8;
13              
14             my ($conf, $tk, $ret);
15             $conf = Unix::Conf::Bind8->new_conf (
16             FILE => '/etc/named.conf',
17             SECURE_OPEN => 1,
18             ) or $conf->die ("couldn't open `named.conf'");
19              
20             #
21             # Ways to get a Trustedkeys object.
22             #
23              
24             $tk = $conf->new_trustedkeys (
25             KEYS => [
26             [ 'extremix.net', 257 255 3 '"AQP2fHpZ4VMpKo/j"' ],
27             [ '.', 257 255 1 '"TjKef0x54VpKod~"' ],
28             ) or $tk->die ("couldn't create trustedkeys");
29              
30             $tk = $conf->get_trustedkeys ()
31             or $tk->die ("couldn't get trustedkeys");
32              
33             #
34             # Operations that can be performed with a trustedkeys object
35             #
36              
37             # set trustedkey for `yahoo.com'
38             $ret = $tk->key ('yahoo.com', 257, 255, 3, '"aRlOs7dOc/a"')
39             or $ret->die ("couldn't set trustedkeys for `yahoo.com'");
40              
41             $ret = $tk->key ('extremix.net')
42             or $ret->die ("couldn't get trustedkeys for `extremix.net'");
43              
44             # traverse all defined keys
45             for my $domain ($tk->domains ()) {
46             for my $alg ($tk->algorithms ()) {
47             $ret = $tk->key ($domain, $alg);
48             print ("@$ret\n");
49             }
50             }
51              
52             # another way
53             my @keys = $tk->trustedkeys ();
54             print "@$_\n" for (@keys);
55              
56             # delete a specific key.
57             # Note that if 3 is the only algorithm defined for `extremix.net', the
58             # domain itself will be deleted from the internal structure. If the domain
59             # `extremix.net' is the only one defined, the invocant object itself if
60             # deleted.
61             $ret = $tk->delete_key ('extremix.net', 3)
62             or $ret->die ("couldn't delete key for `extremix.net', 3");
63              
64             =head1 METHODS
65              
66             =cut
67              
68             package Unix::Conf::Bind8::Conf::Trustedkeys;
69              
70 10     10   54 use strict;
  10         16  
  10         396  
71 10     10   48 use warnings;
  10         20  
  10         280  
72 10     10   49 use Unix::Conf;
  10         17  
  10         184  
73              
74 10     10   49 use Unix::Conf::Bind8::Conf::Directive;
  10         13  
  10         434  
75             our (@ISA) = qw (Unix::Conf::Bind8::Conf::Directive);
76              
77 10     10   49 use Unix::Conf::Bind8::Conf::Lib;
  10         15  
  10         1570  
78              
79              
80             #
81             # This is from DNS & Bind (4th edition) by Paul Albitz and Cricket Liu
82             #
83             # Arguments needed for a trusted key record are
84             #
85             # domain name flags protocol algorithm key
86             #
87             # Format of the flags field
88             # -------------------------
89             #
90             # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
91             # +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
92             # | A/C | Z | XT| Z | Z | NAMTYP| Z | Z | Z | Z | SIG |
93             # +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
94             #
95             # If the value of the first bit is zero, the key can be used for authentication.
96             # This bit is always zero.
97             #
98             # If the value of the second bit is zero, the key can be used for confidentiality.
99             # This bit is always zero for a zones public key.
100             #
101             # The third bit is reserved for future use. For now, its value must be zero.
102             #
103             # The fourth bit is a "flag extenstion" bit. It is designed to provide future
104             # expandability. For now the value must always be zero.
105             #
106             # The fifth and sixth bits are reserved and must be zero.
107             #
108             # The seventh and eighth bits encode the type of key:
109             #
110             # 00
111             # The is the user's key. A mail user agent might use a user's key to encrypt
112             # email addressed to that user. This type of key isn't use in DNSSEC.
113             # 01
114             # This is a zone's public key. All DNSSEC key are this type of key.
115             # 10
116             # This is a host's key. An IPSEC implementation might use a host's key to
117             # encprypt all IP packets sent to that host. DNSSEC keys are this type of key.
118             # 11
119             # Reserved for future use.
120             #
121             # The ninth through twelfth bits are reserved and must be zero. The last four bits
122             # the signatory field, which is now obsolete.
123             #
124             # Format of the protocol field
125             # ----------------------------
126             #
127             # 0 Reserved
128             #
129             # 1 This key is used with Transport Layer Security (TLS), as described in RFC 2246.
130             #
131             # 2 This key is used in connection with email, e.g., an S/MIME key.
132             #
133             # 3 This key is used with DNSSEC. All DNSSEC keys, will have a protocol octet of 3.
134             #
135             # 4 This key is used with IPSEC
136             #
137             # 255
138             # This key is used with any protocol that can use a KEY record.
139             #
140             # All the values between 4 and 255 are unavailable for future assignment.
141             #
142             # Format of the algorithm field
143             # -----------------------------
144             #
145             # 0 Reserved
146             #
147             # 1 RSA/MD5.
148             #
149             # 2 Diffe-Hellman.
150             #
151             # 3 DSA.
152             #
153             # 4. Reserved for an elliptic curve-based public key algorithm.
154             #
155             #
156             # The final field is the public key itself, encoded in base 64.
157             #
158              
159             #
160             # This is how the data is stored
161             # {
162             # domain =>
163             # {
164             # algorithm =>
165             # [
166             # DOMAIN
167             # FLAGS
168             # PROTOCOL
169             # ALGORITHM
170             # KEY
171             # ],
172             # },
173             # }
174             #
175              
176             # Index into the array passed as argument
177 10     10   56 use constant DOMAIN => 0;
  10         16  
  10         868  
178 10     10   47 use constant FLAGS => 1;
  10         17  
  10         441  
179 10     10   46 use constant PROTOCOL => 2;
  10         23  
  10         411  
180 10     10   49 use constant ALGORITHM => 3;
  10         17  
  10         608  
181 10     10   47 use constant KEY => 4;
  10         14  
  10         18173  
182              
183             # Forward declarations
184             sub __valid_protocol ($);
185             sub __valid_algorithm ($);
186              
187             =over 4
188              
189             =item new ()
190              
191             Arguments
192             KEYS => [ domain flags protocol algorithm key ]
193             or
194             KEYS => [ [ domain flags protocol algorithm key ], [..] ]
195             WHERE => 'FIRST'|'LAST'|'BEFORE'|'AFTER'
196             WARG => Unix::Conf::Bind8::Conf::Directive subclass object
197             # WARG is to be provided only in case WHERE eq 'BEFORE
198             # or WHERE eq 'AFTER'
199             PARENT => reference, # to the Conf object datastructure.
200              
201             Class constructor.
202             Creates a new Unix::Conf::Bind8::Conf::Trustedkeys object and returns it,
203             on success, an Err object otherwise. Do not use this constructor directly.
204             Use the Unix::Conf::Bind8::Conf::new_trustedkeys () method instead.
205              
206             =cut
207              
208             sub new
209             {
210 0     0 1   shift ();
211 0           my %args = @_;
212 0           my $new = bless ({});
213 0           my ($parent, $keys, $ret);
214              
215 0 0         $args{PARENT} || return (Unix::Conf->_err ('new', "PARENT not defined"));
216 0 0         $ret = $new->_parent ($args{PARENT}) or return ($ret);
217              
218 0 0         if ($args{KEYS}) {
219 0 0 0       if (ref ($args{KEYS}[0]) && UNIVERSAL::isa ($args{KEYS}[0], 'ARRAY')) {
220 0           $keys = $args{KEYS}
221             }
222             else {
223 0           $keys = [ @{$args{KEYS}} ];
  0            
224             }
225 0           $ret = $new->key (@{$_}) or return ($ret)
226 0   0       for (@$keys);
227             }
228              
229 0 0         $ret = Unix::Conf::Bind8::Conf::_add_trustedkeys ($new)
230             or return ($ret);
231 0 0         $args{WHERE} = 'LAST' unless ($args{WHERE});
232 0 0         $ret = Unix::Conf::Bind8::Conf::_insert_in_list ($new, $args{WHERE}, $args{WARG})
233             or return ($ret);
234 0           return ($new);
235             }
236              
237             =item key ()
238              
239             Arguments
240             DOMAIN
241             FLAGS
242             PROTOCOL
243             ALGORITHM
244             KEY
245              
246             or
247              
248             DOMAIN
249             ALGORITHM
250              
251             Object method.
252             In the first form, sets the key for domain `DOMAIN' and protocol
253             `PROTOCOL' and returns true, on success, an Err object otherwise.
254             In the second form, returns (DOMAIN, FLAGS, PROTOCOL, ALGORITHM, KEY)
255             for the passed domain, algorithm, if defined, an Err object otherwise.
256              
257             =cut
258              
259             sub key
260             {
261 0     0 1   my $self = shift ();
262 0           my ($domain, $algorithm, $args);
263              
264 0 0         if (@_ == 5) { # set
    0          
265 0           $args = [ @_ ];
266 0           __valid_string ($args->[DOMAIN]);
267 0 0         return (Unix::Conf->_err ('key', "illegal protocol value `$args->[PROTOCOL]'"))
268             unless (__valid_protocol ($args->[PROTOCOL]));
269 0 0         return (Unix::Conf->_err ('key', "illegal algorithm value `$args->[ALGORITHM]'"))
270             unless (__valid_algorithm ($args->[ALGORITHM]));
271 0 0         $args->[KEY] = qq("$args->[KEY]") if ($args->[KEY] =~ /^[^"]/);
272 0           $self->{keys}{$args->[DOMAIN]}{$args->[ALGORITHM]} = $args;
273 0           $self->dirty (1);
274 0           return (1);
275             }
276             elsif (@_ == 2) { # get
277 0           ($domain, $algorithm) = @_;
278 0           __valid_string ($domain);
279 0 0         return (Unix::Conf->_err ('key', "illegal algorithm value `$algorithm'"))
280             unless (__valid_algorithm ($algorithm));
281 0           return (Unix::Conf->_err ('key', "no keys for domain `$domain'"))
282 0 0 0       unless ($self->{keys}{$domain} || keys (%{$self->{keys}{$domain}}));
283             return (
284 0           Unix::Conf->_err (
285             'key',
286             "no key with algorithm `$algorithm' defined for domain `$domain'"
287             )
288 0 0 0       ) unless ($self->{keys}{$domain}{$algorithm} || keys (%{$self->{keys}{$domain}}));
289 0           return ( [ @{$self->{keys}{$domain}{$algorithm}} ] );
  0            
290             }
291             else {
292 0           return (Unix::Conf->_err ('key', scalar (@_)." - unexpected number of arguments"));
293             }
294             }
295              
296             =item add_key ()
297              
298             Arguments
299             DOMAIN
300             FLAGS
301             PROTOCOL
302             ALGORITHM
303             KEY
304              
305             Object method.
306             Adds KEY for domain `DOMAIN' and algorithm `ALGORITHM' and returns
307             true, on success, an Err object otherwise.
308              
309             =cut
310              
311             sub add_key
312             {
313 0     0 1   my $self = shift ();
314              
315 0 0         return (Unix::Conf->_err ('add_key', "expected number of arguments 5"))
316             unless (@_ == 5);
317 0           my $args = [ @_ ];
318 0           __valid_string ($args->[DOMAIN]);
319 0 0         return (Unix::Conf->_err ('add_key', "illegal protocol value `$args->[PROTOCOL]'"))
320             unless (__valid_protocol ($args->[PROTOCOL]));
321 0 0         return (Unix::Conf->_err ('add_key', "illegal algorithm value `$args->[ALGORITHM]'"))
322             unless (__valid_algorithm ($args->[ALGORITHM]));
323             return (
324 0 0         Unix::Conf->_err (
325             'add_key',
326             "key for domain `$args->[DOMAIN]' and algorithm `$args->[ALGORITHM]' already defined"
327             )
328             ) if ($self->{keys}{$args->[DOMAIN]}{$args->[ALGORITHM]});
329 0 0         $args->[KEY] = qq("$args->[KEY]") if ($args->[KEY] =~ /^[^"]/);
330 0           $self->{keys}{$args->[DOMAIN]}{$args->[ALGORITHM]} = $args;
331 0           $self->dirty (1);
332 0           return (1);
333             }
334              
335             =item delete_key ()
336              
337             Arguments
338             DOMAIN
339             ALGORITHM # optional
340              
341             Object method.
342             Deletes the KEY for domain `DOMAIN', algorithm `ALGORITHM'. If
343             ALGORITHM is not passed deletes all key for domain `DOMAIN', if
344             defined. If all domains defined are deleted, the object itself is
345             deleted Returns true, an Err object otherwise.
346              
347             =cut
348              
349             sub delete_key
350             {
351 0     0 1   my ($self, $domain, $algorithm) = @_;
352              
353 0           __valid_string ($domain);
354 0 0         return (Unix::Conf->_err ('delete_key', "domain`$domain' not defined"))
355             unless ($self->{keys}{$domain});
356              
357 0 0         if (defined ($algorithm)) {
358 0 0         return (Unix::Conf->_err ('delete_key', "illegal algorithm value `$algorithm'"))
359             unless (__valid_protocol ($algorithm));
360             return (
361 0 0         Unix::Conf->_err (
362             'delete_key',
363             "no key with algorithm `$algorithm' defined for domain `$domain'"
364             )
365             ) unless ($self->{keys}{$domain}{$algorithm});
366 0           delete ($self->{keys}{$domain}{$algorithm});
367 0 0         goto DELKEY_RET if (keys (%{$self->{keys}{$domain}}));
  0            
368             }
369 0           delete ($self->{keys}{$domain});
370 0 0         $self->delete () unless (keys (%{$self->{keys}}));
  0            
371              
372 0           DELKEY_RET:
373             $self->dirty (1);
374 0           return (1);
375             }
376              
377             =item trustedkeys ()
378              
379             Object method.
380             Returns defined keys. When called in list context, returns all defined
381             directives. Iterates over defined keys, when called in scalar context.
382             Returns `undef' at the end of one iteration, and starts over if called
383             again.
384              
385             =cut
386              
387             {
388             my @keys;
389             my $itr = 0;
390             sub trustedkeys
391             {
392 0     0 1   my $self = $_[0];
393            
394             # create a list of keys only if the iterator is at the start
395 0 0         unless ($itr) {
396 0           undef (@keys);
397 0           for my $dom (keys (%{$self->{keys}})) {
  0            
398 0           for my $alg (keys (%{$self->{keys}{$dom}})) {
  0            
399 0           push (@keys, [ @{$self->{keys}{$dom}{$alg}} ]);
  0            
400             }
401             }
402             }
403 0 0         if (wantarray ()) {
404             # reset iterator before returning
405 0           $itr = 0;
406 0           return (@keys);
407             }
408             # return undef on completion of one iteration
409 0 0 0       return () if ($itr && !($itr %= scalar (@keys)));
410 0           return ($keys[$itr++]);
411             }
412             }
413              
414             =item domains ()
415              
416             Object method.
417             Iterates through all defined domains. Returns them one at a time
418             in scalar context, or all of them in list context.
419              
420             =cut
421              
422             sub domains
423             {
424 0     0 1   my $self = $_[0];
425              
426             return (
427 0 0         wantarray () ? keys (%{$self->{keys}}) : (each (%{$self->{keys}}))[0]
  0            
  0            
428             );
429             }
430              
431             =item algorithms ()
432              
433             Arguments
434             DOMAIN
435              
436             Object method.
437             Iterates through all defined algorithms defined for domain `DOMAIN'. Returns
438             them one at a time in scalar context, or all of them in list context.
439              
440             =cut
441              
442             sub algorithms
443             {
444 0     0 1   my ($self, $domain) = @_;
445              
446 0 0         return (Unix::Conf->_err ("domain not passed")) unless (defined ($domain));
447             return (
448 0 0         wantarray () ? keys (%{$self->{keys}{$domain}}) : (each (%{$self->{keys}{$domain}}))[0]
  0            
  0            
449             )
450             }
451              
452             sub __render
453             {
454 0     0     my $self = $_[0];
455 0           my ($rendered, $rec);
456              
457 0           $rendered .= "trusted-keys {\n";
458 0           for my $domain ($self->domains ()) {
459 0           for my $algo ($self->algorithms ($domain)) {
460 0 0         $rec = $self->key ($domain, $algo)
461             or return ($rec);
462 0           $rendered .= "\t@$rec;\n";
463             }
464             }
465 0           $rendered .= "};";
466 0           return ($self->_rstring (\$rendered));
467             }
468              
469             sub __valid_protocol ($)
470             {
471 0 0 0 0     return (1) if (($_[0] >= 0 && $_[0] <= 4) || $_[0] == 255);
      0        
472 0           return ();
473             }
474              
475             sub __valid_algorithm ($)
476             {
477 0 0 0 0     return (1) if ($_[0] >= 0 && $_[0] <= 4);
478 0           return ();
479             }
480              
481             1;