1# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license 2 3# Copyright (C) 2004-2007, 2009-2011 Nominum, Inc. 4# 5# Permission to use, copy, modify, and distribute this software and its 6# documentation for any purpose with or without fee is hereby granted, 7# provided that the above copyright notice and this permission notice 8# appear in all copies. 9# 10# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES 11# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR 13# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 16# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 18import base64 19import calendar 20import struct 21import time 22 23import dns.dnssec 24import dns.exception 25import dns.rdata 26import dns.rdatatype 27 28 29class BadSigTime(dns.exception.DNSException): 30 31 """Time in DNS SIG or RRSIG resource record cannot be parsed.""" 32 33 34def sigtime_to_posixtime(what): 35 if len(what) != 14: 36 raise BadSigTime 37 year = int(what[0:4]) 38 month = int(what[4:6]) 39 day = int(what[6:8]) 40 hour = int(what[8:10]) 41 minute = int(what[10:12]) 42 second = int(what[12:14]) 43 return calendar.timegm((year, month, day, hour, minute, second, 44 0, 0, 0)) 45 46 47def posixtime_to_sigtime(what): 48 return time.strftime('%Y%m%d%H%M%S', time.gmtime(what)) 49 50 51class RRSIG(dns.rdata.Rdata): 52 53 """RRSIG record 54 55 @ivar type_covered: the rdata type this signature covers 56 @type type_covered: int 57 @ivar algorithm: the algorithm used for the sig 58 @type algorithm: int 59 @ivar labels: number of labels 60 @type labels: int 61 @ivar original_ttl: the original TTL 62 @type original_ttl: long 63 @ivar expiration: signature expiration time 64 @type expiration: long 65 @ivar inception: signature inception time 66 @type inception: long 67 @ivar key_tag: the key tag 68 @type key_tag: int 69 @ivar signer: the signer 70 @type signer: dns.name.Name object 71 @ivar signature: the signature 72 @type signature: string""" 73 74 __slots__ = ['type_covered', 'algorithm', 'labels', 'original_ttl', 75 'expiration', 'inception', 'key_tag', 'signer', 76 'signature'] 77 78 def __init__(self, rdclass, rdtype, type_covered, algorithm, labels, 79 original_ttl, expiration, inception, key_tag, signer, 80 signature): 81 super(RRSIG, self).__init__(rdclass, rdtype) 82 self.type_covered = type_covered 83 self.algorithm = algorithm 84 self.labels = labels 85 self.original_ttl = original_ttl 86 self.expiration = expiration 87 self.inception = inception 88 self.key_tag = key_tag 89 self.signer = signer 90 self.signature = signature 91 92 def covers(self): 93 return self.type_covered 94 95 def to_text(self, origin=None, relativize=True, **kw): 96 return '%s %d %d %d %s %s %d %s %s' % ( 97 dns.rdatatype.to_text(self.type_covered), 98 self.algorithm, 99 self.labels, 100 self.original_ttl, 101 posixtime_to_sigtime(self.expiration), 102 posixtime_to_sigtime(self.inception), 103 self.key_tag, 104 self.signer.choose_relativity(origin, relativize), 105 dns.rdata._base64ify(self.signature) 106 ) 107 108 @classmethod 109 def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True): 110 type_covered = dns.rdatatype.from_text(tok.get_string()) 111 algorithm = dns.dnssec.algorithm_from_text(tok.get_string()) 112 labels = tok.get_int() 113 original_ttl = tok.get_ttl() 114 expiration = sigtime_to_posixtime(tok.get_string()) 115 inception = sigtime_to_posixtime(tok.get_string()) 116 key_tag = tok.get_int() 117 signer = tok.get_name() 118 signer = signer.choose_relativity(origin, relativize) 119 chunks = [] 120 while 1: 121 t = tok.get().unescape() 122 if t.is_eol_or_eof(): 123 break 124 if not t.is_identifier(): 125 raise dns.exception.SyntaxError 126 chunks.append(t.value.encode()) 127 b64 = b''.join(chunks) 128 signature = base64.b64decode(b64) 129 return cls(rdclass, rdtype, type_covered, algorithm, labels, 130 original_ttl, expiration, inception, key_tag, signer, 131 signature) 132 133 def to_wire(self, file, compress=None, origin=None): 134 header = struct.pack('!HBBIIIH', self.type_covered, 135 self.algorithm, self.labels, 136 self.original_ttl, self.expiration, 137 self.inception, self.key_tag) 138 file.write(header) 139 self.signer.to_wire(file, None, origin) 140 file.write(self.signature) 141 142 @classmethod 143 def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): 144 header = struct.unpack('!HBBIIIH', wire[current: current + 18]) 145 current += 18 146 rdlen -= 18 147 (signer, cused) = dns.name.from_wire(wire[: current + rdlen], current) 148 current += cused 149 rdlen -= cused 150 if origin is not None: 151 signer = signer.relativize(origin) 152 signature = wire[current: current + rdlen].unwrap() 153 return cls(rdclass, rdtype, header[0], header[1], header[2], 154 header[3], header[4], header[5], header[6], signer, 155 signature) 156 157 def choose_relativity(self, origin=None, relativize=True): 158 self.signer = self.signer.choose_relativity(origin, relativize) 159