1import logging
2import math
3
4math_ceil = math.ceil
5math_log = math.log
6
7from pypacker.structcbs import pack_B
8
9logger = logging.getLogger("pypacker")
10from_bytes = int.from_bytes
11
12"""
13Basic format:
14Type | Length | Content
15> Type
16class | P/C | Tag num | More | Tag num
17
18https://en.wikipedia.org/wiki/X.690#DER_encoding
19"""
20
21
22def encode_length_definitive(num):
23	if num < 0x80:
24		return pack_B(num)
25	else:
26		len_len_inbytes = math_ceil( math_log(num + 1, 256) )
27
28		if len_len_inbytes > 0x7F:
29			logger.warning("Number too big for encoding")
30
31		len_bytesencoded = num.to_bytes(len_len_inbytes, "big")
32		return pack_B(0x80 + len_len_inbytes) + len_bytesencoded
33
34def decode_length_definitive(bts):
35	"""
36	bts -- [len_shortlong:1->127] where bits of len_shortlong = ABBB BBBB [CCCCCCCC].
37		Should be 127 bytes (exact length unknown before calling)
38	return -- lengts of length, length
39	"""
40	vlen = bts[0]
41	# Defnite form: short or long
42	is_lenshort = (vlen & 0x80) == 0
43	# Length of length-bytes
44	len_len = 1
45
46	if not is_lenshort:
47		# The long form consist of 1 initial octet followed by 1 or more subsequent octets,
48		# containing the length. In the initial octet, bit 8 is 1, and bits 1-7 (excluding
49		# the values 0 and 127) encode the number of octets that follow.
50		#logger.debug("Got long format!")
51		len_octets = vlen & 0x7F
52		lenbts = bts[1: 1 + len_octets]
53		#logger.debug("len in bytes: %s" % lenbts)
54		vlen = from_bytes(lenbts, byteorder="big", signed=False)
55		#logger.debug("length longform, bytes: %r (%d) = %d" % (lenbts, len_octets, vlen))
56		len_len += len_octets
57	return len_len, vlen
58
59def _get_der_tlv(der_bts):
60	"""
61	return -- idlen, lenlen, vlen, is_primitive
62	"""
63	off = 0
64	tagstart = off
65	is_primitive = (der_bts[off] & 0x20) == 0
66	# High tag number form
67	# If the tag number is too large for the 5-bit tag field, it has to be encoded in further octets.
68	if (der_bts[off] & 0x1F) == 0x1F:
69		#logger.warning("Got high tag form")
70		# is_hightag = True
71		off += 1
72
73		while (der_bts[off] & 0x80) != 0:
74			off += 1
75	off += 1
76	lenstart = off
77	lenlen, vlen = decode_length_definitive(der_bts[lenstart: lenstart + 127])
78	off += lenlen
79	valuestart = off
80
81	return lenstart - tagstart, valuestart - lenstart, vlen, is_primitive
82
83class LinkedTLVList(list):
84	def __init__(self, val):
85		self._parent_list = None
86		super().__init__(val)
87
88	def set_parent(self, parent_list):
89		self._parent_list = parent_list
90
91	def get_parent(self):
92		return self._parent_list
93
94	def append(self, tlv_list):
95		tlv_list.set_parent(self)
96		super().append(tlv_list)
97
98	def is_primitive(self):
99		# tlv -> (a, b, c), on non-primitive types c will be come a list
100		return len(self) == 3 and type(self[2]) is bytes
101
102	def get_value_raw(self):
103		if len(self) == 3:
104			if self.is_primitive():
105				return self[2]
106			else:
107				return b"".join(v.bin() for v in self[2])
108		elif len(self) == 1:
109			# Assume list in list
110			return self[0].bin()
111		else:
112			raise Exception("%s" % self)
113
114	def bin(self):
115		if len(self) == 3:
116			if self.is_primitive():
117				return self[0] + self[1] + self[2]
118			else:
119				type_len = self[0] + self[1]
120				value = b"".join(v.bin() for v in self[2])
121				return type_len + value
122		elif len(self) == 1:
123			# Assume list in list
124			return self[0].bin()
125		else:
126			raise Exception("%s" % self)
127
128	def update_len_uptoroot(self):
129		self[1] = encode_length_definitive(self.get_value_bin())
130		self.get_parent().update_len_uptoroot()
131
132	def __setitem__(self, idx, val):
133		if not is_primitive():
134			raise Exception("Can't change non-primitive values!")
135
136		# Update lengths if primitive value changed
137		update_needed = self.is_primitive() and idx == 2 and len(val) != len(self[2])
138		super().__setitem__(idx, val)
139
140		if update_needed:
141			logger.debug("Update of length needed")
142			self.update_len_uptoroot()
143
144	"""
145	def __getitem__(self, idx):
146		val_ret = super().__getitem__(idx)
147
148		return LinkedTLVList(val_ret) if type(val_ret) == list else val_ret
149	"""
150
151def decode_der(der_bts, rw_cb=None):
152	off = 0
153	end = len(der_bts)
154	result = LinkedTLVList([])
155
156	while off < end:
157		taglen, lenlen, vlen, prim = _get_der_tlv(der_bts[off:])
158		der_sub = der_bts[off + taglen + lenlen: off + taglen + lenlen + vlen]
159
160		if not prim:
161			der_sub = decode_der(der_sub, rw_cb=rw_cb)
162
163		# Results: [tag_bts, lenlen_bts, value_bts]
164		ltlv = LinkedTLVList([
165			der_bts[off: off + taglen],
166			der_bts[off + taglen: off + taglen + lenlen],
167			der_sub]
168		)
169		#print(ltlv)
170		result.append(ltlv)
171		off += (taglen + lenlen + vlen)
172
173	rw_cb(result)
174
175	return result
176
177"""
178>>> X.509
179
180Certificate  ::=  SEQUENCE  {
181    tbsCertificate       TBSCertificate,
182    signatureAlgorithm   AlgorithmIdentifier,
183    signatureValue       BIT STRING  }
1843082 06eb - SEQUENCE with length 0x06eb
185
186TBSCertificate  ::=  SEQUENCE  {
187    version         [0]  EXPLICIT Version DEFAULT v1,
188    serialNumber         CertificateSerialNumber,
189    signature            AlgorithmIdentifier,
190    issuer               Name,
191    validity             Validity,
192    subject              Name,
193    subjectPublicKeyInfo SubjectPublicKeyInfo,
194    issuerUniqueID  [1]  IMPLICIT UniqueIdentifier OPTIONAL,
195    -- If present, version MUST be v2 or v3
196    subjectUniqueID [2]  IMPLICIT UniqueIdentifier OPTIONAL,
197    -- If present, version MUST be v2 or v3
198    extensions      [3]  EXPLICIT Extensions OPTIONAL
199    -- If present, version MUST be v3
200}
201"""
202
203X509_ID_COMMONNAME		= b"U\x04\x03"
204X509_ID_COUNTRYNAME		= b"U\x04\x06"
205X509_ID_LOCALITYNAME		= b"U\x04\x07"
206X509_ID_STATEORPROVINCENAME	= b"U\x04\x08"
207X509_ID_ORGANIZATIONNAME	= b"U\x04\n"
208X509_ID_ORGANIZATIONUNITNAME	= b"U\x04\x0b"
209
210"""
211http://www.oid-info.com/
212
2132.5.4.0 - id-at-objectClass
2142.5.4.1 - id-at-aliasedEntryName
2152.5.4.2 - id-at-knowldgeinformation
2162.5.4.3 - id-at-commonName
2172.5.4.4 - id-at-surname
2182.5.4.5 - id-at-serialNumber
2192.5.4.6 - id-at-countryName
2202.5.4.7 - id-at-localityName
2212.5.4.8 - id-at-stateOrProvinceName
2222.5.4.9 - id-at-streetAddress
2232.5.4.10 - id-at-organizationName
2242.5.4.11 - id-at-organizationalUnitName
2252.5.4.12 - id-at-title
2262.5.4.13 - id-at-description
2272.5.4.14 - id-at-searchGuide
2282.5.4.15 - id-at-businessCategory
2292.5.4.16 - id-at-postalAddress
2302.5.4.17 - id-at-postalCode
2312.5.4.18 - id-at-postOfficeBox
2322.5.4.19 - id-at-physicalDeliveryOfficeName
2332.5.4.20 - id-at-telephoneNumber
2342.5.4.21 - id-at-telexNumber
2352.5.4.22 - id-at-teletexTerminalIdentifier
2362.5.4.23 - id-at-facsimileTelephoneNumber
2372.5.4.24 - id-at-x121Address
2382.5.4.25 - id-at-internationalISDNNumber
2392.5.4.26 - id-at-registeredAddress
2402.5.4.27 - id-at-destinationIndicator
2412.5.4.28 - id-at-preferredDeliveryMethod
2422.5.4.29 - id-at-presentationAddress
2432.5.4.30 - id-at-supportedApplicationContext
2442.5.4.31 - id-at-member
2452.5.4.32 - id-at-owner
2462.5.4.33 - id-at-roleOccupant
2472.5.4.34 - id-at-seeAlso
2482.5.4.35 - id-at-userPassword
2492.5.4.36 - id-at-userCertificate
2502.5.4.37 - id-at-cACertificate
2512.5.4.38 - id-at-authorityRevocationList
2522.5.4.39 - id-at-certificateRevocationList
2532.5.4.40 - id-at-crossCertificatePair
2542.5.4.41 - id-at-name
2552.5.4.42 - id-at-givenName
2562.5.4.43 - id-at-initials
2572.5.4.44 - id-at-generationQualifier
2582.5.4.45 - id-at-uniqueIdentifier
2592.5.4.46 - id-at-dnQualifier
2602.5.4.47 - id-at-enhancedSearchGuide
2612.5.4.48 - id-at-protocolInformation
2622.5.4.49 - id-at-distinguishedName
2632.5.4.50 - id-at-uniqueMember
2642.5.4.51 - id-at-houseIdentifier
2652.5.4.52 - id-at-supportedAlgorithms
2662.5.4.53 - id-at-deltaRevocationList
2672.5.4.58 - Attribute Certificate attribute (id-at-attributeCertificate)
2682.5.4.65 - id-at-pseudonym
269
270
2712.5.29.1 - old Authority Key Identifier
2722.5.29.2 - old Primary Key Attributes
2732.5.29.3 - Certificate Policies
2742.5.29.4 - Primary Key Usage Restriction
2752.5.29.9 - Subject Directory Attributes
2762.5.29.14 - Subject Key Identifier
2772.5.29.15 - Key Usage
2782.5.29.16 - Private Key Usage Period
2792.5.29.17 - Subject Alternative Name
2802.5.29.18 - Issuer Alternative Name
2812.5.29.19 - Basic Constraints
2822.5.29.20 - CRL Number
2832.5.29.21 - Reason code
2842.5.29.23 - Hold Instruction Code
2852.5.29.24 - Invalidity Date
2862.5.29.27 - Delta CRL indicator
2872.5.29.28 - Issuing Distribution Point
2882.5.29.29 - Certificate Issuer
2892.5.29.30 - Name Constraints
2902.5.29.31 - CRL Distribution Points
2912.5.29.32 - Certificate Policies
2922.5.29.33 - Policy Mappings
2932.5.29.35 - Authority Key Identifier
2942.5.29.36 - Policy Constraints
2952.5.29.37 - Extended key usage
2962.5.29.46 - FreshestCRL
2972.5.29.54 - X.509 version 3 certificate extension Inhibit Any-policy
298
299"""
300
301