summaryrefslogtreecommitdiff
path: root/lib/Crypto/Util
diff options
context:
space:
mode:
authorLegrandin <gooksankoo@hoiptorrow.mailexpire.com>2011-01-13 00:22:58 +0100
committerLegrandin <gooksankoo@hoiptorrow.mailexpire.com>2011-01-13 00:22:58 +0100
commite74df2ad6a342c0642cd8cb5a185a769b702299d (patch)
treee638801a01a295d1ac4151cdec6388ed09e6a279 /lib/Crypto/Util
parentabd276c5fa31abf0b1d70ca4624e30cdacaee867 (diff)
downloadpycrypto-e74df2ad6a342c0642cd8cb5a185a769b702299d.tar.gz
Added DocStrings to all DER classes.
DerInteger.decode raises an exception if no INTEGER tag is found.
Diffstat (limited to 'lib/Crypto/Util')
-rw-r--r--lib/Crypto/Util/asn1.py149
1 files changed, 111 insertions, 38 deletions
diff --git a/lib/Crypto/Util/asn1.py b/lib/Crypto/Util/asn1.py
index ceaf3eb..06ed175 100644
--- a/lib/Crypto/Util/asn1.py
+++ b/lib/Crypto/Util/asn1.py
@@ -25,76 +25,134 @@ from Crypto.Util.number import long_to_bytes, bytes_to_long
__all__ = [ 'DerObject', 'DerInteger', 'DerSequence' ]
class DerObject:
+ """Base class for defining a single DER object.
+
+ Instantiate this class ONLY when you have to decode a DER element.
+ """
+
+ # Known TAG types
typeTags = { 'SEQUENCE':'\x30', 'BIT STRING':'\x03', 'INTEGER':'\x02' }
def __init__(self, ASN1Type=None):
- self.typeTag = self.typeTags.get(ASN1Type, ASN1Type)
+ """Initialize the DER object according to a specific type.
+
+ The ASN.1 type is either specified as the ASN.1 string (e.g.
+ 'SEQUENCE'), directly with its numerical tag or with no tag
+ atl all (None)."""
+ self.typeTag = self.typeTags.get(ASN1Type, ASN1Type)
self.payload = ''
def _lengthOctets(self, payloadLen):
- '''
- Return an octet string that is suitable for the BER/DER
- length element if the relevant payload is of the given
- size (in bytes).
- '''
+ """Return a string that encodes the given payload length (in
+ bytes) in a format suitable for a DER length tag (L).
+ """
if payloadLen>127:
encoding = long_to_bytes(payloadLen)
return chr(len(encoding)+128) + encoding
return chr(payloadLen)
def encode(self):
+ """Return a complete DER element, fully encoded as a TLV."""
return self.typeTag + self._lengthOctets(len(self.payload)) + self.payload
def _decodeLen(self, idx, str):
- '''
- Given a string and an index to a DER LV,
- this function returns a tuple with the length of V
- and an index to the first byte of it.
- '''
- length = ord(str[idx])
+ """Given a (part of a) DER element, and an index to the first byte of
+ a DER length tag (L), return a tuple with the payload size,
+ and the index of the first byte of the such payload (V).
+
+ Raises a ValueError exception if the DER length is invalid.
+ Raises an IndexError exception if the DER element is too short.
+ """
+ length = ord(str[idx])
if length<=127:
return (length,idx+1)
- else:
- payloadLength = bytes_to_long(str[idx+1:idx+1+(length & 0x7F)])
- if payloadLength<=127:
- raise ValueError("Not a DER length tag.")
- return (payloadLength, idx+1+(length & 0x7F))
+ payloadLength = bytes_to_long(str[idx+1:idx+1+(length & 0x7F)])
+ if payloadLength<=127:
+ raise ValueError("Not a DER length tag.")
+ return (payloadLength, idx+1+(length & 0x7F))
- def decode(self, input, noLeftOvers=0):
- try:
- self.typeTag = input[0]
+ def decode(self, derEle, noLeftOvers=0):
+ """Decode a complete DER element, and re-initializes this
+ object with it.
+
+ @param derEle A complete DER element. It must start with a DER T
+ tag.
+ @param noLeftOvers Indicate whether it is acceptable to complete the
+ parsing of the DER element and find that not all
+ bytes in derEle have been used.
+ @return Index of the first unused byte in the given DER element.
+
+ Raises a ValueError exception in case of parsing errors.
+ Raises an IndexError exception if the DER element is too short.
+ """
+ try:
+ self.typeTag = derEle[0]
if (ord(self.typeTag) & 0x1F)==0x1F:
raise ValueError("Unsupported DER tag")
- (length,idx) = self._decodeLen(1,input)
- if noLeftOvers and len(input) != (idx+length):
+ (length,idx) = self._decodeLen(1, derEle)
+ if noLeftOvers and len(derEle) != (idx+length):
raise ValueError("Not a DER structure")
- self.payload = input[idx:idx+length]
+ self.payload = derEle[idx:idx+length]
except IndexError:
raise ValueError("Not a valid DER SEQUENCE.")
return idx+length
class DerInteger(DerObject):
def __init__(self, value = 0):
+ """Class to model an INTEGER DER element.
+
+ Limitation: only non-negative values are supported.
+ """
DerObject.__init__(self, 'INTEGER')
self.value = value
def encode(self):
+ """Return a complete INTEGER DER element, fully encoded as a TLV."""
self.payload = long_to_bytes(self.value)
if ord(self.payload[0])>127:
self.payload = '\x00' + self.payload
return DerObject.encode(self)
- def decode(self, input, noLeftOvers=0):
- tlvLength = DerObject.decode(self, input,noLeftOvers)
+ def decode(self, derEle, noLeftOvers=0):
+ """Decode a complete INTEGER DER element, and re-initializes this
+ object with it.
+
+ @param derEle A complete INTEGER DER element. It must start with a DER
+ INTEGER tag.
+ @param noLeftOvers Indicate whether it is acceptable to complete the
+ parsing of the DER element and find that not all
+ bytes in derEle have been used.
+ @return Index of the first unused byte in the given DER element.
+
+ Raises a ValueError exception if the DER element is not a
+ valid non-negative INTEGER.
+ Raises an IndexError exception if the DER element is too short.
+ """
+ tlvLength = DerObject.decode(self, derEle, noLeftOvers)
+ if self.typeTag!=self.typeTags['INTEGER']:
+ raise ValueError ("Not a DER INTEGER.")
if ord(self.payload[0])>127:
raise ValueError ("Negative INTEGER.")
self.value = bytes_to_long(self.payload)
return tlvLength
class DerSequence(DerObject):
+ """Class to model a SEQUENCE DER element.
+
+ This object behave like a dynamic Python sequence.
+ Sub-elements that are INTEGERs, look like Python integers.
+ Any other sub-element is a binary string encoded as the complete DER
+ sub-element (TLV).
+ """
+
def __init__(self):
+ """Initialize the SEQUENCE DER object. Always empty
+ initially."""
DerObject.__init__(self, 'SEQUENCE')
self._seq = []
+
+ ## A few methods to make it behave like a python sequence
+
def __delitem__(self, n):
del self._seq[n]
def __getitem__(self, n):
@@ -113,6 +171,7 @@ class DerSequence(DerObject):
return self._seq.append(item)
def hasOnlyInts(self):
+ """Return 1/True is all items in this sequence are numbers."""
if not self._seq: return 0
test = 0
for item in self._seq:
@@ -123,11 +182,13 @@ class DerSequence(DerObject):
return 1
def encode(self):
- '''
- Return the DER encoding for the ASN.1 SEQUENCE containing
- the non-negative integers and longs added to this object.
- '''
- self.payload = ''
+ """Return the DER encoding for the ASN.1 SEQUENCE, containing
+ the non-negative integers and longs added to this object.
+
+ Limitation: Raises a ValueError exception if it some elements
+ in the sequence are neither Python integers nor complete DER INTEGERs.
+ """
+ self.payload = ''
for item in self._seq:
try:
self.payload += item
@@ -138,16 +199,28 @@ class DerSequence(DerObject):
raise ValueError("Trying to DER encode an unknown object")
return DerObject.encode(self)
- def decode(self, input,noLeftOvers=0):
- '''
- This function decodes the given string into a sequence of
- ASN.1 objects. Yet, we only know about unsigned INTEGERs.
- Any other type is stored as its rough TLV. In the latter
- case, the correctectness of the TLV is not checked.
- '''
+ def decode(self, derEle, noLeftOvers=0):
+ """Decode a complete SEQUENCE DER element, and re-initializes this
+ object with it.
+
+ @param derEle A complete SEQUENCE DER element. It must start with a DER
+ SEQUENCE tag.
+ @param noLeftOvers Indicate whether it is acceptable to complete the
+ parsing of the DER element and find that not all
+ bytes in derEle have been used.
+ @return Index of the first unused byte in the given DER element.
+
+ DER INTEGERs are decoded into Python integers. Any other DER
+ element is not decoded. Its validity is not checked.
+
+ Raises a ValueError exception if the DER element is not a
+ valid DER SEQUENCE.
+ Raises an IndexError exception if the DER element is too short.
+ """
+
self._seq = []
try:
- tlvLength = DerObject.decode(self, input,noLeftOvers)
+ tlvLength = DerObject.decode(self, derEle, noLeftOvers)
if self.typeTag!=self.typeTags['SEQUENCE']:
raise ValueError("Not a DER SEQUENCE.")
# Scan one TLV at once