Skip to content

Commit 0e711ea

Browse files
committed
Modify Dump example
1 parent d0f3981 commit 0e711ea

3 files changed

Lines changed: 156 additions & 35 deletions

File tree

examples/Dump/asn1.pyi

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
import io
2+
from builtins import bytes
3+
from builtins import int
4+
from enum import IntEnum
5+
from typing import Any
6+
from typing import Generator
7+
from typing import NamedTuple
8+
9+
from _typeshed import Incomplete
10+
11+
INDEFINITE_FORM: int
12+
13+
class Asn1Enum(IntEnum): ...
14+
15+
class Numbers(Asn1Enum):
16+
Boolean = 1
17+
Integer = 2
18+
BitString = 3
19+
OctetString = 4
20+
Null = 5
21+
ObjectIdentifier = 6
22+
ObjectDescriptor = 7
23+
External = 8
24+
Real = 9
25+
Enumerated = 10
26+
EmbeddedPDV = 11
27+
UTF8String = 12
28+
RelativeOID = 13
29+
Time = 14
30+
Sequence = 16
31+
Set = 17
32+
NumericString = 18
33+
PrintableString = 19
34+
T61String = 20
35+
VideotextString = 21
36+
IA5String = 22
37+
UTCTime = 23
38+
GeneralizedTime = 24
39+
GraphicString = 25
40+
VisibleString = 26
41+
GeneralString = 27
42+
UniversalString = 28
43+
CharacterString = 29
44+
UnicodeString = 30
45+
Date = 31
46+
TimeOfDay = 32
47+
DateTime = 33
48+
Duration = 34
49+
OIDinternationalized = 35
50+
RelativeOIDinternationalized = 36
51+
52+
class Types(Asn1Enum):
53+
Constructed = 32
54+
Primitive = 0
55+
56+
class Classes(Asn1Enum):
57+
Universal = 0
58+
Application = 64
59+
Context = 128
60+
Private = 192
61+
62+
class ReadFlags(IntEnum):
63+
OnlyValue = 0
64+
WithUnused = 1
65+
66+
class Tag(NamedTuple):
67+
nr: Incomplete
68+
typ: Incomplete
69+
cls: Incomplete
70+
71+
def to_int_2c(values: bytes) -> int: ...
72+
def to_bytes_2c(value: int) -> bytes: ...
73+
def shift_bits_right(values, unused): ...
74+
def is_negative_zero(x): ...
75+
def is_positive_infinity(x): ...
76+
def is_negative_infinity(x): ...
77+
def is_nan(x): ...
78+
def is_iterable(value): ...
79+
80+
class Error(Exception): ...
81+
82+
class Encoder:
83+
def __init__(self) -> None: ...
84+
def start(self, stream: io.RawIOBase | None = None) -> None: ...
85+
def enter(self, nr: int, cls: int | None = None) -> None: ...
86+
def leave(self) -> None: ...
87+
def construct(self, nr: int, cls: int | None = None) -> Generator[None, Any, None]: ...
88+
def write(self, value: Any, nr: int | None = None, typ: int | None = None, cls: int | None = None) -> None: ...
89+
def output(self) -> bytes: ...
90+
91+
class Decoder:
92+
def __init__(self) -> None: ...
93+
def start(self, stream: io.RawIOBase | bytes) -> None: ...
94+
def peek(self) -> Tag | None: ...
95+
def read(self, flags: ReadFlags = ...) -> tuple[Tag | None, Any]: ...
96+
def eof(self) -> bool: ...
97+
def enter(self) -> None: ...
98+
def leave(self) -> None: ...
Lines changed: 58 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -8,43 +8,65 @@
88
# the file "AUTHORS" for a complete overview.
99

1010
from __future__ import absolute_import, division, print_function, unicode_literals
11+
1112
from builtins import open, bytes, str
12-
import sys
13+
import asn1
1314
import base64
1415
import binascii
15-
16-
import asn1
16+
import io
17+
import sys
18+
import typing
1719
import optparse
1820

1921

20-
def read_pem(input_file):
21-
"""Read PEM formatted input."""
22-
data = []
23-
state = 0
24-
for line in input_file:
25-
if state == 0:
26-
if line.startswith('-----BEGIN'):
27-
state = 1
28-
elif state == 1:
29-
if line.startswith('-----END'):
30-
state = 2
31-
else:
32-
data.append(line)
33-
elif state == 2:
34-
break
35-
if state != 2:
36-
raise ValueError('No PEM encoded input found')
37-
data = ''.join(data)
38-
return base64.b64decode(data)
22+
class PEMBinaryIO(io.RawIOBase):
23+
"""A RawIOBase implementation that reads and writes PEM encoded data."""
24+
def __init__(self, stream):
25+
self._stream = stream
26+
self._buffer = b''
27+
self._state = 0
28+
29+
def read(self, size=-1):
30+
while size < 0 or len(self._buffer) < size:
31+
line = self._stream.readline()
32+
if not line:
33+
break
34+
line = line.strip()
35+
36+
if self._state == 0:
37+
if line.startswith('-----BEGIN'):
38+
self._state = 1
39+
elif self._state == 1:
40+
if line.startswith('-----END'):
41+
self._state = 2
42+
else:
43+
self._buffer += base64.b64decode(line)
44+
45+
# All data?
46+
if size < 0:
47+
data, self._buffer = self._buffer, b''
48+
return data
49+
50+
# Only a portion of the data
51+
data, self._buffer = self._buffer[:size], self._buffer[size:]
52+
return data
53+
54+
def write(self, data):
55+
self._stream.write(base64.b64encode(data).decode('ascii'))
56+
self._stream.write('\n')
57+
58+
def close(self):
59+
self._stream.close()
3960

4061

4162
tag_id_to_string_map = {
4263
asn1.Numbers.Boolean: "BOOLEAN",
4364
asn1.Numbers.Integer: "INTEGER",
4465
asn1.Numbers.BitString: "BIT STRING",
45-
asn1.Numbers.OctetString: "OCTET STRING",
4666
asn1.Numbers.Null: "NULL",
47-
asn1.Numbers.ObjectIdentifier: "OBJECT",
67+
asn1.Numbers.OctetString: "OCTET STRING",
68+
asn1.Numbers.ObjectIdentifier: "OBJECT IDENTIFIER",
69+
asn1.Numbers.ObjectDescriptor: "OBJECT DESCRIPTOR",
4870
asn1.Numbers.PrintableString: "PRINTABLESTRING",
4971
asn1.Numbers.IA5String: "IA5STRING",
5072
asn1.Numbers.UTCTime: "UTCTIME",
@@ -117,12 +139,11 @@ def object_identifier_to_string(identifier):
117139
return object_id_to_string_map[identifier]
118140
return identifier
119141

120-
121142
def value_to_string(tag_number, value):
122143
if tag_number == asn1.Numbers.ObjectIdentifier:
123144
return object_identifier_to_string(value)
124145
elif isinstance(value, bytes):
125-
return '0x' + str(binascii.hexlify(value).upper())
146+
return str(binascii.hexlify(value, ' ', 1).upper(), encoding='ascii')
126147
elif isinstance(value, str):
127148
return value
128149
else:
@@ -133,6 +154,8 @@ def pretty_print(input_stream, output_stream, indent=0):
133154
"""Pretty print ASN.1 data."""
134155
while not input_stream.eof():
135156
tag = input_stream.peek()
157+
if tag is None:
158+
return
136159
if tag.typ == asn1.Types.Primitive:
137160
tag, value = input_stream.read()
138161
output_stream.write(' ' * indent)
@@ -149,24 +172,24 @@ def pretty_print(input_stream, output_stream, indent=0):
149172

150173
parser = optparse.OptionParser()
151174
parser.add_option('-p', '--pem', dest='mode', action='store_const', const='pem', help='PEM encoded input')
152-
parser.add_option('-r', '--raw', dest='mode', action='store_const', const='raw', help='raw input')
153175
parser.add_option('-o', '--output', dest='output', help='output to FILE instead', metavar='FILE')
154176
parser.set_default('mode', 'pem')
155177
(opts, args) = parser.parse_args()
156178

179+
if len(args) != 1:
180+
parser.error('Please provide an input file')
181+
exit(1)
182+
183+
decoder = asn1.Decoder()
184+
157185
if opts.mode == 'pem':
158-
input_file = open(args[0], 'r')
159-
input_data = read_pem(input_file)
186+
decoder.start(PEMBinaryIO(open(args[0], 'r')))
160187
else:
161-
input_file = open(args[0], 'rb')
162-
input_data = input_file.read()
188+
decoder.start(typing.cast(io.RawIOBase, open(args[0], 'rb')))
163189

164190
if opts.output:
165191
output_file = open(opts.output, 'w')
166192
else:
167-
output_file = sys.stdout
168-
169-
decoder = asn1.Decoder()
170-
decoder.start(input_data)
193+
output_file = typing.cast(io.TextIOWrapper, sys.stdout)
171194

172195
pretty_print(decoder, output_file)

0 commit comments

Comments
 (0)