Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 60 additions & 1 deletion lib/Crypto/Util/asn1.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

import struct

from Crypto.Util.py3compat import byte_string, bchr, bord
from Crypto.Util.py3compat import byte_string, bchr, bord, is_bytes

from Crypto.Util.number import long_to_bytes, bytes_to_long

Expand All @@ -45,6 +45,40 @@ def _is_number(x, only_non_negative=False):
return not only_non_negative or x >= 0


def _try_decode(maybe_der_encoded):
"""Internal helper function to be called within DerObject.__repr__().
Not general-purpose."""

try:
if not is_bytes(maybe_der_encoded):
raise TypeError()
tag_octet = maybe_der_encoded[0]
if (tag_octet & 0x80) and (tag_octet & 0x20):
# constructed and context-specific; assuming EXPLICIT
tag_octet = maybe_der_encoded[1]
asn1id = tag_octet & 0x1f
if asn1id == 0x01:
return DerBoolean().decode(maybe_der_encoded)
if asn1id == 0x02:
return DerInteger().decode(maybe_der_encoded)
if asn1id == 0x03:
return DerBitString().decode(maybe_der_encoded)
if asn1id == 0x04:
return DerOctetString().decode(maybe_der_encoded)
if asn1id == 0x05:
return DerNull().decode(maybe_der_encoded)
if asn1id == 0x06:
return DerObjectId().decode(maybe_der_encoded)
if asn1id == 0x10:
return DerSequence().decode(maybe_der_encoded)
if asn1id == 0x11:
return DerSetOf().decode(maybe_der_encoded)
# Sometimes, a bytestring is just a bytestring...
return maybe_der_encoded
except (TypeError, ValueError, IndexError):
return maybe_der_encoded


class BytesIO_EOF(object):
"""This class differs from BytesIO in that a ValueError exception is
raised whenever EOF is reached."""
Expand Down Expand Up @@ -258,6 +292,28 @@ def _decodeFromStream(self, s, strict):
if p.remaining_data() > 0:
raise ValueError("Unexpected extra data after the DER structure")

def __repr__(self):
tag_octet = self._tag_octet
# is_constructed = bool(tag_octet & 0x20)
is_overridden = bool(tag_octet & 0x80)
is_explicit = hasattr(self, '_inner_tag_octet')
asn1id = tag_octet & 0x1f
if hasattr(self, 'value'):
# non-sequence types with a native Python value
args_repr = repr(self.value)
elif hasattr(self, '_seq'):
# sequence types
args_repr = repr(list(map(_try_decode, self._seq)))
else:
# non-sequence types with no native Python value
args_repr = repr(_try_decode(self.payload))
if is_overridden:
if not is_explicit:
args_repr += ', implicit=%i' % (asn1id, )
else:
args_repr += ', explicit=%i' % (asn1id, )
return '%s(%s)' % (self.__class__.__name__, args_repr)


class DerInteger(DerObject):
"""Class to model a DER INTEGER.
Expand Down Expand Up @@ -696,6 +752,9 @@ def __init__(self):

DerObject.__init__(self, 0x05, b'', None, False)

def __repr__(self):
return '%s()' % (self.__class__.__name__, )


class DerObjectId(DerObject):
"""Class to model a DER OBJECT ID.
Expand Down