Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / ui / userdata / asn1.py @ 5facd191

History | View | Annotate | Download (5 kB)

1 8bf3a249 Kostas Papadimitriou
# ===================================================================
2 8bf3a249 Kostas Papadimitriou
# The contents of this file are dedicated to the public domain.  To
3 8bf3a249 Kostas Papadimitriou
# the extent that dedication to the public domain is not available,
4 8bf3a249 Kostas Papadimitriou
# everyone is granted a worldwide, perpetual, royalty-free,
5 8bf3a249 Kostas Papadimitriou
# non-exclusive license to exercise all rights associated with the
6 8bf3a249 Kostas Papadimitriou
# contents of this file for any purpose whatsoever.
7 8bf3a249 Kostas Papadimitriou
# No rights are reserved.
8 8bf3a249 Kostas Papadimitriou
#
9 8bf3a249 Kostas Papadimitriou
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
10 8bf3a249 Kostas Papadimitriou
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
11 8bf3a249 Kostas Papadimitriou
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
12 8bf3a249 Kostas Papadimitriou
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
13 8bf3a249 Kostas Papadimitriou
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
14 8bf3a249 Kostas Papadimitriou
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
15 8bf3a249 Kostas Papadimitriou
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
16 8bf3a249 Kostas Papadimitriou
# SOFTWARE.
17 8bf3a249 Kostas Papadimitriou
# ===================================================================
18 8bf3a249 Kostas Papadimitriou
19 8bf3a249 Kostas Papadimitriou
from Crypto.Util.number import long_to_bytes, bytes_to_long
20 8bf3a249 Kostas Papadimitriou
21 8bf3a249 Kostas Papadimitriou
__all__ = [ 'DerObject', 'DerInteger', 'DerSequence' ]
22 8bf3a249 Kostas Papadimitriou
23 8bf3a249 Kostas Papadimitriou
class DerObject:
24 8bf3a249 Kostas Papadimitriou
        typeTags = { 'SEQUENCE':'\x30', 'BIT STRING':'\x03', 'INTEGER':'\x02' }
25 8bf3a249 Kostas Papadimitriou
26 8bf3a249 Kostas Papadimitriou
        def __init__(self, ASN1Type=None):
27 8bf3a249 Kostas Papadimitriou
                self.typeTag = self.typeTags.get(ASN1Type, ASN1Type)
28 8bf3a249 Kostas Papadimitriou
                self.payload = ''
29 8bf3a249 Kostas Papadimitriou
30 8bf3a249 Kostas Papadimitriou
        def _lengthOctets(self, payloadLen):
31 8bf3a249 Kostas Papadimitriou
                '''
32 8bf3a249 Kostas Papadimitriou
                Return an octet string that is suitable for the BER/DER
33 8bf3a249 Kostas Papadimitriou
                length element if the relevant payload is of the given
34 8bf3a249 Kostas Papadimitriou
                size (in bytes).
35 8bf3a249 Kostas Papadimitriou
                '''
36 8bf3a249 Kostas Papadimitriou
                if payloadLen>127:
37 8bf3a249 Kostas Papadimitriou
                        encoding = long_to_bytes(payloadLen)
38 8bf3a249 Kostas Papadimitriou
                        return chr(len(encoding)+128) + encoding
39 8bf3a249 Kostas Papadimitriou
                return chr(payloadLen)
40 8bf3a249 Kostas Papadimitriou
41 8bf3a249 Kostas Papadimitriou
        def encode(self):
42 8bf3a249 Kostas Papadimitriou
                return self.typeTag + self._lengthOctets(len(self.payload)) + self.payload
43 8bf3a249 Kostas Papadimitriou
44 8bf3a249 Kostas Papadimitriou
        def _decodeLen(self, idx, str):
45 8bf3a249 Kostas Papadimitriou
                '''
46 8bf3a249 Kostas Papadimitriou
                Given a string and an index to a DER LV,
47 8bf3a249 Kostas Papadimitriou
                this function returns a tuple with the length of V
48 8bf3a249 Kostas Papadimitriou
                and an index to the first byte of it.
49 8bf3a249 Kostas Papadimitriou
                '''
50 8bf3a249 Kostas Papadimitriou
                length = ord(str[idx])
51 8bf3a249 Kostas Papadimitriou
                if length<=127:
52 8bf3a249 Kostas Papadimitriou
                        return (length,idx+1)
53 8bf3a249 Kostas Papadimitriou
                else:
54 8bf3a249 Kostas Papadimitriou
                        payloadLength = bytes_to_long(str[idx+1:idx+1+(length & 0x7F)])
55 8bf3a249 Kostas Papadimitriou
                        if payloadLength<=127:
56 8bf3a249 Kostas Papadimitriou
                                raise ValueError("Not a DER length tag.")
57 8bf3a249 Kostas Papadimitriou
                        return (payloadLength, idx+1+(length & 0x7F))
58 8bf3a249 Kostas Papadimitriou
59 8bf3a249 Kostas Papadimitriou
        def decode(self, input, noLeftOvers=0):
60 8bf3a249 Kostas Papadimitriou
                try:
61 8bf3a249 Kostas Papadimitriou
                        self.typeTag = input[0]
62 8bf3a249 Kostas Papadimitriou
                        if (ord(self.typeTag) & 0x1F)==0x1F:
63 8bf3a249 Kostas Papadimitriou
                                raise ValueError("Unsupported DER tag")
64 8bf3a249 Kostas Papadimitriou
                        (length,idx) = self._decodeLen(1,input)
65 8bf3a249 Kostas Papadimitriou
                        if noLeftOvers and len(input) != (idx+length):
66 8bf3a249 Kostas Papadimitriou
                                raise ValueError("Not a DER structure")
67 8bf3a249 Kostas Papadimitriou
                        self.payload = input[idx:idx+length]
68 8bf3a249 Kostas Papadimitriou
                except IndexError:
69 8bf3a249 Kostas Papadimitriou
                        raise ValueError("Not a valid DER SEQUENCE.")
70 8bf3a249 Kostas Papadimitriou
                return idx+length
71 8bf3a249 Kostas Papadimitriou
72 8bf3a249 Kostas Papadimitriou
class DerInteger(DerObject):
73 8bf3a249 Kostas Papadimitriou
        def __init__(self, value = 0):
74 8bf3a249 Kostas Papadimitriou
                DerObject.__init__(self, 'INTEGER')
75 8bf3a249 Kostas Papadimitriou
                self.value = value
76 8bf3a249 Kostas Papadimitriou
77 8bf3a249 Kostas Papadimitriou
        def encode(self):
78 8bf3a249 Kostas Papadimitriou
                self.payload = long_to_bytes(self.value)
79 8bf3a249 Kostas Papadimitriou
                if ord(self.payload[0])>127:
80 8bf3a249 Kostas Papadimitriou
                        self.payload = '\x00' + self.payload
81 8bf3a249 Kostas Papadimitriou
                return DerObject.encode(self)
82 8bf3a249 Kostas Papadimitriou
83 8bf3a249 Kostas Papadimitriou
        def decode(self, input, noLeftOvers=0):
84 8bf3a249 Kostas Papadimitriou
                tlvLength = DerObject.decode(self, input,noLeftOvers)
85 8bf3a249 Kostas Papadimitriou
                if ord(self.payload[0])>127:
86 8bf3a249 Kostas Papadimitriou
                        raise ValueError ("Negative INTEGER.")
87 8bf3a249 Kostas Papadimitriou
                self.value = bytes_to_long(self.payload)
88 8bf3a249 Kostas Papadimitriou
                return tlvLength
89 8bf3a249 Kostas Papadimitriou
90 8bf3a249 Kostas Papadimitriou
class DerSequence(DerObject):
91 8bf3a249 Kostas Papadimitriou
        def __init__(self):
92 8bf3a249 Kostas Papadimitriou
                DerObject.__init__(self, 'SEQUENCE')
93 8bf3a249 Kostas Papadimitriou
                self._seq = []
94 8bf3a249 Kostas Papadimitriou
        def __delitem__(self, n):
95 8bf3a249 Kostas Papadimitriou
                del self._seq[n]
96 8bf3a249 Kostas Papadimitriou
        def __getitem__(self, n):
97 8bf3a249 Kostas Papadimitriou
                return self._seq[n]
98 8bf3a249 Kostas Papadimitriou
        def __setitem__(self, key, value):
99 8bf3a249 Kostas Papadimitriou
                self._seq[key] = value
100 8bf3a249 Kostas Papadimitriou
        def __setslice__(self,i,j,sequence):
101 8bf3a249 Kostas Papadimitriou
                self._seq[i:j] = sequence
102 8bf3a249 Kostas Papadimitriou
        def __delslice__(self,i,j):
103 8bf3a249 Kostas Papadimitriou
                del self._seq[i:j]
104 8bf3a249 Kostas Papadimitriou
        def __getslice__(self, i, j):
105 8bf3a249 Kostas Papadimitriou
                return self._seq[max(0, i):max(0, j)]
106 8bf3a249 Kostas Papadimitriou
        def __len__(self):
107 8bf3a249 Kostas Papadimitriou
                return len(self._seq)
108 8bf3a249 Kostas Papadimitriou
        def append(self, item):
109 8bf3a249 Kostas Papadimitriou
                return self._seq.append(item)
110 8bf3a249 Kostas Papadimitriou
111 8bf3a249 Kostas Papadimitriou
        def hasOnlyInts(self):
112 8bf3a249 Kostas Papadimitriou
                if not self._seq: return 0
113 8bf3a249 Kostas Papadimitriou
                test = 0
114 8bf3a249 Kostas Papadimitriou
                for item in self._seq:
115 8bf3a249 Kostas Papadimitriou
                        try:
116 8bf3a249 Kostas Papadimitriou
                                test += item
117 8bf3a249 Kostas Papadimitriou
                        except TypeError:
118 8bf3a249 Kostas Papadimitriou
                                return 0
119 8bf3a249 Kostas Papadimitriou
                return 1
120 8bf3a249 Kostas Papadimitriou
121 8bf3a249 Kostas Papadimitriou
        def encode(self):
122 8bf3a249 Kostas Papadimitriou
                '''
123 8bf3a249 Kostas Papadimitriou
                Return the DER encoding for the ASN.1 SEQUENCE containing
124 8bf3a249 Kostas Papadimitriou
                the non-negative integers and longs added to this object.
125 8bf3a249 Kostas Papadimitriou
                '''
126 8bf3a249 Kostas Papadimitriou
                self.payload = ''
127 8bf3a249 Kostas Papadimitriou
                for item in self._seq:
128 8bf3a249 Kostas Papadimitriou
                        try:
129 8bf3a249 Kostas Papadimitriou
                                self.payload += item
130 8bf3a249 Kostas Papadimitriou
                        except:
131 8bf3a249 Kostas Papadimitriou
                                try:
132 8bf3a249 Kostas Papadimitriou
                                        self.payload += DerInteger(item).encode()
133 8bf3a249 Kostas Papadimitriou
                                except:
134 8bf3a249 Kostas Papadimitriou
                                        raise ValueError("Trying to DER encode an unknown object")
135 8bf3a249 Kostas Papadimitriou
                return DerObject.encode(self)
136 8bf3a249 Kostas Papadimitriou
137 8bf3a249 Kostas Papadimitriou
        def decode(self, input,noLeftOvers=0):
138 8bf3a249 Kostas Papadimitriou
                '''
139 8bf3a249 Kostas Papadimitriou
                This function decodes the given string into a sequence of
140 8bf3a249 Kostas Papadimitriou
                ASN.1 objects. Yet, we only know about unsigned INTEGERs.
141 8bf3a249 Kostas Papadimitriou
                Any other type is stored as its rough TLV. In the latter
142 8bf3a249 Kostas Papadimitriou
                case, the correctectness of the TLV is not checked.
143 8bf3a249 Kostas Papadimitriou
                '''
144 8bf3a249 Kostas Papadimitriou
                self._seq = []
145 8bf3a249 Kostas Papadimitriou
                try:
146 8bf3a249 Kostas Papadimitriou
                        tlvLength = DerObject.decode(self, input,noLeftOvers)
147 8bf3a249 Kostas Papadimitriou
                        if self.typeTag!=self.typeTags['SEQUENCE']:
148 8bf3a249 Kostas Papadimitriou
                                raise ValueError("Not a DER SEQUENCE.")
149 8bf3a249 Kostas Papadimitriou
                        # Scan one TLV at once
150 8bf3a249 Kostas Papadimitriou
                        idx = 0
151 8bf3a249 Kostas Papadimitriou
                        while idx<len(self.payload):
152 8bf3a249 Kostas Papadimitriou
                                typeTag = self.payload[idx]
153 8bf3a249 Kostas Papadimitriou
                                if typeTag==self.typeTags['INTEGER']:
154 8bf3a249 Kostas Papadimitriou
                                        newInteger = DerInteger()
155 8bf3a249 Kostas Papadimitriou
                                        idx += newInteger.decode(self.payload[idx:])
156 8bf3a249 Kostas Papadimitriou
                                        self._seq.append(newInteger.value)
157 8bf3a249 Kostas Papadimitriou
                                else:
158 8bf3a249 Kostas Papadimitriou
                                        itemLen,itemIdx = self._decodeLen(idx+1,self.payload)
159 8bf3a249 Kostas Papadimitriou
                                        self._seq.append(self.payload[idx:itemIdx+itemLen])
160 8bf3a249 Kostas Papadimitriou
                                        idx = itemIdx + itemLen
161 8bf3a249 Kostas Papadimitriou
                except IndexError:
162 8bf3a249 Kostas Papadimitriou
                        raise ValueError("Not a valid DER SEQUENCE.")
163 8bf3a249 Kostas Papadimitriou
                return tlvLength