| Index: third_party/google-endpoints/Crypto/Util/asn1.py
|
| diff --git a/third_party/google-endpoints/Crypto/Util/asn1.py b/third_party/google-endpoints/Crypto/Util/asn1.py
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..dd5ec31d4a8d400976943c7e7a1cf23435d8f646
|
| --- /dev/null
|
| +++ b/third_party/google-endpoints/Crypto/Util/asn1.py
|
| @@ -0,0 +1,286 @@
|
| +# -*- coding: ascii -*-
|
| +#
|
| +# Util/asn1.py : Minimal support for ASN.1 DER binary encoding.
|
| +#
|
| +# ===================================================================
|
| +# The contents of this file are dedicated to the public domain. To
|
| +# the extent that dedication to the public domain is not available,
|
| +# everyone is granted a worldwide, perpetual, royalty-free,
|
| +# non-exclusive license to exercise all rights associated with the
|
| +# contents of this file for any purpose whatsoever.
|
| +# No rights are reserved.
|
| +#
|
| +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
| +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
| +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
| +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
| +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
| +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
| +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
| +# SOFTWARE.
|
| +# ===================================================================
|
| +
|
| +from Crypto.Util.number import long_to_bytes, bytes_to_long
|
| +import sys
|
| +from Crypto.Util.py3compat import *
|
| +
|
| +__all__ = [ 'DerObject', 'DerInteger', 'DerOctetString', 'DerNull', 'DerSequence', 'DerObjectId' ]
|
| +
|
| +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': 0x30, 'BIT STRING': 0x03, 'INTEGER': 0x02,
|
| + 'OCTET STRING': 0x04, 'NULL': 0x05, 'OBJECT IDENTIFIER': 0x06 }
|
| +
|
| + def __init__(self, ASN1Type=None, payload=b('')):
|
| + """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
|
| + at all (None)."""
|
| + if isInt(ASN1Type) or ASN1Type is None:
|
| + self.typeTag = ASN1Type
|
| + else:
|
| + if len(ASN1Type)==1:
|
| + self.typeTag = ord(ASN1Type)
|
| + else:
|
| + self.typeTag = self.typeTags.get(ASN1Type)
|
| + self.payload = payload
|
| +
|
| + def isType(self, ASN1Type):
|
| + return self.typeTags[ASN1Type]==self.typeTag
|
| +
|
| + def _lengthOctets(self, payloadLen):
|
| + """Return a byte 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 bchr(len(encoding)+128) + encoding
|
| + return bchr(payloadLen)
|
| +
|
| + def encode(self):
|
| + """Return a complete DER element, fully encoded as a TLV."""
|
| + return bchr(self.typeTag) + self._lengthOctets(len(self.payload)) + self.payload
|
| +
|
| + def _decodeLen(self, idx, der):
|
| + """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 = bord(der[idx])
|
| + if length<=127:
|
| + return (length,idx+1)
|
| + payloadLength = bytes_to_long(der[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, 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 = bord(derEle[0])
|
| + if (self.typeTag & 0x1F)==0x1F:
|
| + raise ValueError("Unsupported DER tag")
|
| + (length,idx) = self._decodeLen(1, derEle)
|
| + if noLeftOvers and len(derEle) != (idx+length):
|
| + raise ValueError("Not a DER structure")
|
| + 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 bord(self.payload[0])>127:
|
| + self.payload = bchr(0x00) + self.payload
|
| + return DerObject.encode(self)
|
| +
|
| + 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 bord(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, startSeq=None):
|
| + """Initialize the SEQUENCE DER object. Always empty
|
| + initially."""
|
| + DerObject.__init__(self, 'SEQUENCE')
|
| + if startSeq==None:
|
| + self._seq = []
|
| + else:
|
| + self._seq = startSeq
|
| +
|
| + ## A few methods to make it behave like a python sequence
|
| +
|
| + def __delitem__(self, n):
|
| + del self._seq[n]
|
| + def __getitem__(self, n):
|
| + return self._seq[n]
|
| + def __setitem__(self, key, value):
|
| + self._seq[key] = value
|
| + def __setslice__(self,i,j,sequence):
|
| + self._seq[i:j] = sequence
|
| + def __delslice__(self,i,j):
|
| + del self._seq[i:j]
|
| + def __getslice__(self, i, j):
|
| + return self._seq[max(0, i):max(0, j)]
|
| + def __len__(self):
|
| + return len(self._seq)
|
| + def append(self, item):
|
| + return self._seq.append(item)
|
| +
|
| + def hasInts(self):
|
| + """Return the number of items in this sequence that are numbers."""
|
| + return len(filter(isInt, self._seq))
|
| +
|
| + def hasOnlyInts(self):
|
| + """Return True if all items in this sequence are numbers."""
|
| + return self._seq and self.hasInts()==len(self._seq)
|
| +
|
| + def encode(self):
|
| + """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 = b('')
|
| + for item in self._seq:
|
| + try:
|
| + self.payload += item
|
| + except:
|
| + try:
|
| + self.payload += DerInteger(item).encode()
|
| + except:
|
| + raise ValueError("Trying to DER encode an unknown object")
|
| + return DerObject.encode(self)
|
| +
|
| + 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, derEle, noLeftOvers)
|
| + if self.typeTag!=self.typeTags['SEQUENCE']:
|
| + raise ValueError("Not a DER SEQUENCE.")
|
| + # Scan one TLV at once
|
| + idx = 0
|
| + while idx<len(self.payload):
|
| + typeTag = bord(self.payload[idx])
|
| + if typeTag==self.typeTags['INTEGER']:
|
| + newInteger = DerInteger()
|
| + idx += newInteger.decode(self.payload[idx:])
|
| + self._seq.append(newInteger.value)
|
| + else:
|
| + itemLen,itemIdx = self._decodeLen(idx+1,self.payload)
|
| + self._seq.append(self.payload[idx:itemIdx+itemLen])
|
| + idx = itemIdx + itemLen
|
| + except IndexError:
|
| + raise ValueError("Not a valid DER SEQUENCE.")
|
| + return tlvLength
|
| +
|
| +class DerOctetString(DerObject):
|
| + def __init__(self, value = b('')):
|
| + DerObject.__init__(self, 'OCTET STRING')
|
| + self.payload = value
|
| +
|
| + def decode(self, derEle, noLeftOvers=0):
|
| + p = DerObject.decode(derEle, noLeftOvers)
|
| + if not self.isType("OCTET STRING"):
|
| + raise ValueError("Not a valid OCTET STRING.")
|
| + return p
|
| +
|
| +class DerNull(DerObject):
|
| + def __init__(self):
|
| + DerObject.__init__(self, 'NULL')
|
| +
|
| +class DerObjectId(DerObject):
|
| + def __init__(self):
|
| + DerObject.__init__(self, 'OBJECT IDENTIFIER')
|
| +
|
| + def decode(self, derEle, noLeftOvers=0):
|
| + p = DerObject.decode(derEle, noLeftOvers)
|
| + if not self.isType("OBJECT IDENTIFIER"):
|
| + raise ValueError("Not a valid OBJECT IDENTIFIER.")
|
| + return p
|
| +
|
| +def isInt(x):
|
| + test = 0
|
| + try:
|
| + test += x
|
| + except TypeError:
|
| + return 0
|
| + return 1
|
| +
|
|
|