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