1# Copyright (C) 2003-2007, 2009, 2010 Nominum, Inc. 2# 3# Permission to use, copy, modify, and distribute this software and its 4# documentation for any purpose with or without fee is hereby granted, 5# provided that the above copyright notice and this permission notice 6# appear in all copies. 7# 8# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES 9# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR 11# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 14# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 16import cStringIO 17import struct 18 19import dns.exception 20import dns.dnssec 21import dns.rdata 22import dns.tokenizer 23 24_ctype_by_value = { 25 1 : 'PKIX', 26 2 : 'SPKI', 27 3 : 'PGP', 28 253 : 'URI', 29 254 : 'OID', 30 } 31 32_ctype_by_name = { 33 'PKIX' : 1, 34 'SPKI' : 2, 35 'PGP' : 3, 36 'URI' : 253, 37 'OID' : 254, 38 } 39 40def _ctype_from_text(what): 41 v = _ctype_by_name.get(what) 42 if not v is None: 43 return v 44 return int(what) 45 46def _ctype_to_text(what): 47 v = _ctype_by_value.get(what) 48 if not v is None: 49 return v 50 return str(what) 51 52class CERT(dns.rdata.Rdata): 53 """CERT record 54 55 @ivar certificate_type: certificate type 56 @type certificate_type: int 57 @ivar key_tag: key tag 58 @type key_tag: int 59 @ivar algorithm: algorithm 60 @type algorithm: int 61 @ivar certificate: the certificate or CRL 62 @type certificate: string 63 @see: RFC 2538""" 64 65 __slots__ = ['certificate_type', 'key_tag', 'algorithm', 'certificate'] 66 67 def __init__(self, rdclass, rdtype, certificate_type, key_tag, algorithm, 68 certificate): 69 super(CERT, self).__init__(rdclass, rdtype) 70 self.certificate_type = certificate_type 71 self.key_tag = key_tag 72 self.algorithm = algorithm 73 self.certificate = certificate 74 75 def to_text(self, origin=None, relativize=True, **kw): 76 certificate_type = _ctype_to_text(self.certificate_type) 77 return "%s %d %s %s" % (certificate_type, self.key_tag, 78 dns.dnssec.algorithm_to_text(self.algorithm), 79 dns.rdata._base64ify(self.certificate)) 80 81 def from_text(cls, rdclass, rdtype, tok, origin = None, relativize = True): 82 certificate_type = _ctype_from_text(tok.get_string()) 83 key_tag = tok.get_uint16() 84 algorithm = dns.dnssec.algorithm_from_text(tok.get_string()) 85 if algorithm < 0 or algorithm > 255: 86 raise dns.exception.SyntaxError("bad algorithm type") 87 chunks = [] 88 while 1: 89 t = tok.get().unescape() 90 if t.is_eol_or_eof(): 91 break 92 if not t.is_identifier(): 93 raise dns.exception.SyntaxError 94 chunks.append(t.value) 95 b64 = ''.join(chunks) 96 certificate = b64.decode('base64_codec') 97 return cls(rdclass, rdtype, certificate_type, key_tag, 98 algorithm, certificate) 99 100 from_text = classmethod(from_text) 101 102 def to_wire(self, file, compress = None, origin = None): 103 prefix = struct.pack("!HHB", self.certificate_type, self.key_tag, 104 self.algorithm) 105 file.write(prefix) 106 file.write(self.certificate) 107 108 def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin = None): 109 prefix = wire[current : current + 5] 110 current += 5 111 rdlen -= 5 112 if rdlen < 0: 113 raise dns.exception.FormError 114 (certificate_type, key_tag, algorithm) = struct.unpack("!HHB", prefix) 115 certificate = wire[current : current + rdlen] 116 return cls(rdclass, rdtype, certificate_type, key_tag, algorithm, 117 certificate) 118 119 from_wire = classmethod(from_wire) 120 121 def _cmp(self, other): 122 f = cStringIO.StringIO() 123 self.to_wire(f) 124 wire1 = f.getvalue() 125 f.seek(0) 126 f.truncate() 127 other.to_wire(f) 128 wire2 = f.getvalue() 129 f.close() 130 131 return cmp(wire1, wire2) 132