1
+ # -*- coding: utf-8 -*-
1
2
#
2
3
# This file is part of Python-ASN1. Python-ASN1 is free software that is
3
4
# made available under the MIT license. Consult the file "LICENSE" that
4
5
# is distributed together with this file for the exact licensing terms.
5
6
#
6
- # Python-ASN1 is copyright (c) 2007-2008 by the Python-ASN1 authors. See
7
+ # Python-ASN1 is copyright (c) 2007-2016 by the Python-ASN1 authors. See
7
8
# the file "AUTHORS" for a complete overview.
8
9
10
+ from __future__ import absolute_import , division , print_function , unicode_literals
11
+ from builtins import open , bytes , str
9
12
import sys
10
- import os .path
13
+ import base64
14
+ import binascii
11
15
12
16
import asn1
13
17
import optparse
14
18
15
- def read_pem (input ):
19
+
20
+ def read_pem (input_file ):
16
21
"""Read PEM formatted input."""
17
22
data = []
18
23
state = 0
19
- for line in input :
24
+ for line in input_file :
20
25
if state == 0 :
21
26
if line .startswith ('-----BEGIN' ):
22
27
state = 1
@@ -28,104 +33,139 @@ def read_pem(input):
28
33
elif state == 2 :
29
34
break
30
35
if state != 2 :
31
- raise ValueError , 'No PEM encoded input found'
36
+ raise ValueError ( 'No PEM encoded input found' )
32
37
data = '' .join (data )
33
- data = data .decode ('base64' )
34
- return data
38
+ return base64 .b64decode (data )
39
+
40
+
41
+ tag_id_to_string_map = {
42
+ asn1 .Boolean : "BOOLEAN" ,
43
+ asn1 .Integer : "INTEGER" ,
44
+ asn1 .BitString : "BIT STRING" ,
45
+ asn1 .OctetString : "OCTET STRING" ,
46
+ asn1 .Null : "NULL" ,
47
+ asn1 .ObjectIdentifier : "OBJECT" ,
48
+ asn1 .PrintableString : "PRINTABLESTRING" ,
49
+ asn1 .IA5String : "IA5STRING" ,
50
+ asn1 .UTCTime : "UTCTIME" ,
51
+ asn1 .Enumerated : "ENUMERATED" ,
52
+ asn1 .Sequence : "SEQUENCE" ,
53
+ asn1 .Set : "SET"
54
+ }
55
+
56
+ class_id_to_string_map = {
57
+ asn1 .ClassUniversal : "U" ,
58
+ asn1 .ClassApplication : "A" ,
59
+ asn1 .ClassContext : "C" ,
60
+ asn1 .ClassPrivate : "P"
61
+ }
62
+
63
+ object_id_to_string_map = {
64
+ "1.2.840.113549.1.1.1" : "rsaEncryption" ,
65
+ "1.2.840.113549.1.1.5" : "sha1WithRSAEncryption" ,
66
+
67
+ "1.3.6.1.5.5.7.1.1" : "authorityInfoAccess" ,
68
+
69
+ "2.5.4.3" : "commonName" ,
70
+ "2.5.4.4" : "surname" ,
71
+ "2.5.4.5" : "serialNumber" ,
72
+ "2.5.4.6" : "countryName" ,
73
+ "2.5.4.7" : "localityName" ,
74
+ "2.5.4.8" : "stateOrProvinceName" ,
75
+ "2.5.4.9" : "streetAddress" ,
76
+ "2.5.4.10" : "organizationName" ,
77
+ "2.5.4.11" : "organizationalUnitName" ,
78
+ "2.5.4.12" : "title" ,
79
+ "2.5.4.13" : "description" ,
80
+ "2.5.4.42" : "givenName" ,
81
+
82
+ "1.2.840.113549.1.9.1" : "emailAddress" ,
83
+
84
+ "2.5.29.14" : "X509v3 Subject Key Identifier" ,
85
+ "2.5.29.15" : "X509v3 Key Usage" ,
86
+ "2.5.29.16" : "X509v3 Private Key Usage Period" ,
87
+ "2.5.29.17" : "X509v3 Subject Alternative Name" ,
88
+ "2.5.29.18" : "X509v3 Issuer Alternative Name" ,
89
+ "2.5.29.19" : "X509v3 Basic Constraints" ,
90
+ "2.5.29.30" : "X509v3 Name Constraints" ,
91
+ "2.5.29.31" : "X509v3 CRL Distribution Points" ,
92
+ "2.5.29.32" : "X509v3 Certificate Policies Extension" ,
93
+ "2.5.29.33" : "X509v3 Policy Mappings" ,
94
+ "2.5.29.35" : "X509v3 Authority Key Identifier" ,
95
+ "2.5.29.36" : "X509v3 Policy Constraints" ,
96
+ "2.5.29.37" : "X509v3 Extended Key Usage"
97
+ }
98
+
35
99
36
- def strid ( id ):
100
+ def tag_id_to_string ( identifier ):
37
101
"""Return a string representation of a ASN.1 id."""
38
- if id == asn1 .Boolean :
39
- s = 'BOOLEAN'
40
- elif id == asn1 .Integer :
41
- s = 'INTEGER'
42
- elif id == asn1 .OctetString :
43
- s = 'OCTET STRING'
44
- elif id == asn1 .Null :
45
- s = 'NULL'
46
- elif id == asn1 .ObjectIdentifier :
47
- s = 'OBJECT IDENTIFIER'
48
- elif id == asn1 .Enumerated :
49
- s = 'ENUMERATED'
50
- elif id == asn1 .Sequence :
51
- s = 'SEQUENCE'
52
- elif id == asn1 .Set :
53
- s = 'SET'
54
- elif id == asn1 .Null :
55
- s = 'NULL'
56
- else :
57
- s = '%#02x' % id
58
- return s
59
-
60
- def strclass (id ):
102
+ if identifier in tag_id_to_string_map :
103
+ return tag_id_to_string_map [identifier ]
104
+ return '{:#02x}' .format (identifier )
105
+
106
+
107
+ def class_id_to_string (identifier ):
61
108
"""Return a string representation of an ASN.1 class."""
62
- if id == asn1 .ClassUniversal :
63
- s = 'UNIVERSAL'
64
- elif id == asn1 .ClassApplication :
65
- s = 'APPLICATION'
66
- elif id == asn1 .ClassContext :
67
- s = 'CONTEXT'
68
- elif id == san1 .ClassPrivate :
69
- s = 'PRIVATE'
109
+ if identifier in class_id_to_string_map :
110
+ return class_id_to_string_map [identifier ]
111
+ raise ValueError ('Illegal class: {:#02x}' .format (identifier ))
112
+
113
+
114
+ def object_identifier_to_string (identifier ):
115
+ if identifier in object_id_to_string_map :
116
+ return object_id_to_string_map [identifier ]
117
+ return identifier
118
+
119
+
120
+ def value_to_string (tag_number , value ):
121
+ if isinstance (value , bytes ):
122
+ return '0x' + str (binascii .hexlify (value ).upper ())
123
+ elif isinstance (value , str ):
124
+ return value
125
+ elif tag_number == asn1 .ObjectIdentifier :
126
+ return object_identifier_to_string (value )
70
127
else :
71
- raise ValueError , 'Illegal class: %#02x' % id
72
- return s
128
+ return repr (value )
73
129
74
- def strtag (tag ):
75
- """Return a string represenation of an ASN.1 tag."""
76
- return '[%s] %s' % (strid (tag [0 ]), strclass (tag [2 ]))
77
130
78
- def prettyprint ( input , output , indent = 0 ):
131
+ def pretty_print ( input_stream , output_stream , indent = 0 ):
79
132
"""Pretty print ASN.1 data."""
80
- while not input .eof ():
81
- tag = input .peek ()
82
- if tag [1 ] == asn1 .TypePrimitive :
83
- tag , value = input .read ()
84
- output .write (' ' * indent )
85
- output .write ('[%s] %s (value %s)' %
86
- (strclass (tag [2 ]), strid (tag [0 ]), repr (value )))
87
- output .write ('\n ' )
88
- elif tag [1 ] == asn1 .TypeConstructed :
89
- output .write (' ' * indent )
90
- output .write ('[%s] %s:\n ' % (strclass (tag [2 ]), strid (tag [0 ])))
91
- input .enter ()
92
- prettyprint (input , output , indent + 2 )
93
- input .leave ()
133
+ while not input_stream .eof ():
134
+ tag = input_stream .peek ()
135
+ if tag .typ == asn1 .TypePrimitive :
136
+ tag , value = input_stream .read ()
137
+ output_stream .write (' ' * indent )
138
+ output_stream .write ('[{}] {}: {}\n ' .format (class_id_to_string (tag .cls ), tag_id_to_string (tag .nr ), value_to_string (tag .nr , value )))
139
+ elif tag .typ == asn1 .TypeConstructed :
140
+ output_stream .write (' ' * indent )
141
+ output_stream .write ('[{}] {}\n ' .format (class_id_to_string (tag .cls ), tag_id_to_string (tag .nr )))
142
+ input_stream .enter ()
143
+ pretty_print (input_stream , output_stream , indent + 2 )
144
+ input_stream .leave ()
94
145
95
146
96
147
# Main script
97
148
98
149
parser = optparse .OptionParser ()
99
- parser .add_option ('-p' , '--pem' , dest = 'mode' , action = 'store_const' ,
100
- const = 'pem' , help = 'PEM encoded input' )
101
- parser .add_option ('-r' , '--raw' , dest = 'mode' , action = 'store_const' ,
102
- const = 'raw' , help = 'raw input' )
103
- parser .add_option ('-o' , '--output' , dest = 'output' ,
104
- help = 'output to FILE instead' , metavar = 'FILE' )
150
+ parser .add_option ('-p' , '--pem' , dest = 'mode' , action = 'store_const' , const = 'pem' , help = 'PEM encoded input' )
151
+ parser .add_option ('-r' , '--raw' , dest = 'mode' , action = 'store_const' , const = 'raw' , help = 'raw input' )
152
+ parser .add_option ('-o' , '--output' , dest = 'output' , help = 'output to FILE instead' , metavar = 'FILE' )
105
153
parser .set_default ('mode' , 'pem' )
106
154
(opts , args ) = parser .parse_args ()
107
155
108
- if len (args ) == 1 :
109
- input = file (sys .argv [1 ])
110
- else :
111
- input = sys .stdin
112
-
113
156
if opts .mode == 'pem' :
114
- input = read_pem (input )
157
+ input_file = open (sys .argv [1 ], 'r' )
158
+ input_data = read_pem (input_file )
115
159
else :
116
- input = input .read ()
160
+ input_file = open (sys .argv [1 ], 'rb' )
161
+ input_data = input_file .read ()
117
162
118
163
if opts .output :
119
- output = file (opts .output , 'w' )
164
+ output_file = open (opts .output , 'w' )
120
165
else :
121
- output = sys .stdout
122
-
123
- data = []
124
- for line in input :
125
- data .append (line )
126
- data = '' .join (data )
166
+ output_file = sys .stdout
127
167
128
- dec = asn1 .Decoder ()
129
- dec .start (data )
168
+ decoder = asn1 .Decoder ()
169
+ decoder .start (input_data )
130
170
131
- prettyprint ( dec , output )
171
+ pretty_print ( decoder , output_file )
0 commit comments