Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / userdata / asn1.py @ b47b110d

History | View | Annotate | Download (5 kB)

1
# ===================================================================
2
# The contents of this file are dedicated to the public domain.  To
3
# the extent that dedication to the public domain is not available,
4
# everyone is granted a worldwide, perpetual, royalty-free,
5
# non-exclusive license to exercise all rights associated with the
6
# contents of this file for any purpose whatsoever.
7
# No rights are reserved.
8
#
9
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
10
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
11
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
12
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
13
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
14
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
15
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
16
# SOFTWARE.
17
# ===================================================================
18

    
19
from Crypto.Util.number import long_to_bytes, bytes_to_long
20

    
21
__all__ = [ 'DerObject', 'DerInteger', 'DerSequence' ]
22

    
23
class DerObject:
24
        typeTags = { 'SEQUENCE':'\x30', 'BIT STRING':'\x03', 'INTEGER':'\x02' }
25

    
26
        def __init__(self, ASN1Type=None):
27
                self.typeTag = self.typeTags.get(ASN1Type, ASN1Type)
28
                self.payload = ''
29

    
30
        def _lengthOctets(self, payloadLen):
31
                '''
32
                Return an octet string that is suitable for the BER/DER
33
                length element if the relevant payload is of the given
34
                size (in bytes).
35
                '''
36
                if payloadLen>127:
37
                        encoding = long_to_bytes(payloadLen)
38
                        return chr(len(encoding)+128) + encoding
39
                return chr(payloadLen)
40

    
41
        def encode(self):
42
                return self.typeTag + self._lengthOctets(len(self.payload)) + self.payload
43

    
44
        def _decodeLen(self, idx, str):
45
                '''
46
                Given a string and an index to a DER LV,
47
                this function returns a tuple with the length of V
48
                and an index to the first byte of it.
49
                '''
50
                length = ord(str[idx])
51
                if length<=127:
52
                        return (length,idx+1)
53
                else:
54
                        payloadLength = bytes_to_long(str[idx+1:idx+1+(length & 0x7F)])
55
                        if payloadLength<=127:
56
                                raise ValueError("Not a DER length tag.")
57
                        return (payloadLength, idx+1+(length & 0x7F))
58

    
59
        def decode(self, input, noLeftOvers=0):
60
                try:
61
                        self.typeTag = input[0]
62
                        if (ord(self.typeTag) & 0x1F)==0x1F:
63
                                raise ValueError("Unsupported DER tag")
64
                        (length,idx) = self._decodeLen(1,input)
65
                        if noLeftOvers and len(input) != (idx+length):
66
                                raise ValueError("Not a DER structure")
67
                        self.payload = input[idx:idx+length]
68
                except IndexError:
69
                        raise ValueError("Not a valid DER SEQUENCE.")
70
                return idx+length
71

    
72
class DerInteger(DerObject):
73
        def __init__(self, value = 0):
74
                DerObject.__init__(self, 'INTEGER')
75
                self.value = value
76

    
77
        def encode(self):
78
                self.payload = long_to_bytes(self.value)
79
                if ord(self.payload[0])>127:
80
                        self.payload = '\x00' + self.payload
81
                return DerObject.encode(self)
82

    
83
        def decode(self, input, noLeftOvers=0):
84
                tlvLength = DerObject.decode(self, input,noLeftOvers)
85
                if ord(self.payload[0])>127:
86
                        raise ValueError ("Negative INTEGER.")
87
                self.value = bytes_to_long(self.payload)
88
                return tlvLength
89

    
90
class DerSequence(DerObject):
91
        def __init__(self):
92
                DerObject.__init__(self, 'SEQUENCE')
93
                self._seq = []
94
        def __delitem__(self, n):
95
                del self._seq[n]
96
        def __getitem__(self, n):
97
                return self._seq[n]
98
        def __setitem__(self, key, value):
99
                self._seq[key] = value
100
        def __setslice__(self,i,j,sequence):
101
                self._seq[i:j] = sequence
102
        def __delslice__(self,i,j):
103
                del self._seq[i:j]
104
        def __getslice__(self, i, j):
105
                return self._seq[max(0, i):max(0, j)]
106
        def __len__(self):
107
                return len(self._seq)
108
        def append(self, item):
109
                return self._seq.append(item)
110

    
111
        def hasOnlyInts(self):
112
                if not self._seq: return 0
113
                test = 0
114
                for item in self._seq:
115
                        try:
116
                                test += item
117
                        except TypeError:
118
                                return 0
119
                return 1
120

    
121
        def encode(self):
122
                '''
123
                Return the DER encoding for the ASN.1 SEQUENCE containing
124
                the non-negative integers and longs added to this object.
125
                '''
126
                self.payload = ''
127
                for item in self._seq:
128
                        try:
129
                                self.payload += item
130
                        except:
131
                                try:
132
                                        self.payload += DerInteger(item).encode()
133
                                except:
134
                                        raise ValueError("Trying to DER encode an unknown object")
135
                return DerObject.encode(self)
136

    
137
        def decode(self, input,noLeftOvers=0):
138
                '''
139
                This function decodes the given string into a sequence of
140
                ASN.1 objects. Yet, we only know about unsigned INTEGERs.
141
                Any other type is stored as its rough TLV. In the latter
142
                case, the correctectness of the TLV is not checked.
143
                '''
144
                self._seq = []
145
                try:
146
                        tlvLength = DerObject.decode(self, input,noLeftOvers)
147
                        if self.typeTag!=self.typeTags['SEQUENCE']:
148
                                raise ValueError("Not a DER SEQUENCE.")
149
                        # Scan one TLV at once
150
                        idx = 0
151
                        while idx<len(self.payload):
152
                                typeTag = self.payload[idx]
153
                                if typeTag==self.typeTags['INTEGER']:
154
                                        newInteger = DerInteger()
155
                                        idx += newInteger.decode(self.payload[idx:])
156
                                        self._seq.append(newInteger.value)
157
                                else:
158
                                        itemLen,itemIdx = self._decodeLen(idx+1,self.payload)
159
                                        self._seq.append(self.payload[idx:itemIdx+itemLen])
160
                                        idx = itemIdx + itemLen
161
                except IndexError:
162
                        raise ValueError("Not a valid DER SEQUENCE.")
163
                return tlvLength
164