root / snfcycladesapp / synnefo / userdata / asn1.py @ 0dae1b9f
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, royaltyfree,

5 
# nonexclusive 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 nonnegative 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 