def _decode_value(cls, buf, strict=True): """Decode from a string or string buffer.""" if buf in _OID_DECODING_DICT: return _OID_DECODING_DICT[buf] if not buf: raise error.ASN1Error("Invalid encoding") int_bytes = bytearray(buf) # Last byte can't have the high bit set. if int_bytes[-1] & 0x80: raise error.ASN1Error("Invalid encoding") components = [] first, int_bytes = cls._read_component(int_bytes) if first < 40: components += [0, first] elif first < 80: components += [1, first - 40] else: components += [2, first - 80] while int_bytes: component, int_bytes = cls._read_component(int_bytes) components.append(component) return tuple(components)
def _read_component(cls, int_bytes): """Parse a single component from a non-empty bytearray. Args: int_bytes: a non-empty bytearray. Returns: a (component, rest) tuple with the decoded integer and the remaining bytes of the bytearray. """ ret = 0 i = 0 while int_bytes[i] & 0x80: num = int_bytes[i] & 0x7f if not ret and not num: # The component must be encoded with as few digits as possible, # i.e., leading zeroes are not allowed. Since ASN.1 libraries # interpret leading 0x80-octets differently, this may be # indicative of an attempt to trick a browser into accepting a # certificate it shouldn't. See page 7 of # www.cosic.esat.kuleuven.be/publications/article-1432.pdf raise error.ASN1Error("Leading 0x80 octets in the base-128 " "encoding of OID component") ret |= num ret <<= 7 i += 1 ret |= int_bytes[i] return ret, int_bytes[i + 1:]
def __init__(self, value=None, serialized_value=None, strict=True): super(IPAddress, self).__init__(value=value, serialized_value=serialized_value, strict=strict) if strict and len(self._value) != 4 and len(self._value) != 16: raise error.ASN1Error("%s is not a valid IP address", self.value.encode("hex"))
def __init__(self, value=None, serialized_value=None, strict=True): super(BaseTime, self).__init__(value=value, serialized_value=serialized_value, strict=strict) self._gmtime = self._decode_gmtime(strict=strict) # This is a lenient "strict": if we were able to decode the time, # even if it didn't fully conform to the standard, then we'll allow it. # If the time string is garbage then we raise. if strict and self._gmtime is None: raise error.ASN1Error("Corrupt time: %s" % self._value)
def gmtime(self): """GMT time. Returns: a time.struct_time struct. Raises: error.ASN1Error: the ASN.1 string does not represent a valid time. """ if self._gmtime is None: raise error.ASN1Error("Corrupt time: %s" % self._value) return self._gmtime
def attributes(self, attr_type): """Get a flat list of attribute values of the given type. Returns: a list of attributes. Raises: error.ASN1Error: corrupt attribute value. """ attrs = self.flatten() decoded_values = [attr["value"].decoded_value for attr in attrs if attr["type"] == attr_type] if any([val is None for val in decoded_values]): raise error.ASN1Error("Corrupt name attribute") # A subject name attribute is always a DirectoryString (a Choice), # so we need to take its value. return [d.component_value() for d in decoded_values]
def __init__(self, der_string, strict_der=True): """Initialize from a DER string. Args: der_string: a binary string containing the DER-encoded certificate. strict_der: if False, tolerate some non-fatal DER errors. Raises: error.ASN1Error: invalid encoding. """ # ASN.1 errors fall through. self._asn1_cert = x509.Certificate.decode(der_string, strict=strict_der) # The general philosophy here is that a certificate decoded in # strict mode should never raise CertificateErrors later on in the # code. Strict mode already catches corrupt extensions, to the extent # that their IDs are recognized; in addition, we have to ensure that # no extension appears more than once. # TODO(ekasper): move this check to the Extensions class. if strict_der and self._has_multiple_extension_values(): raise error.ASN1Error("Multiple extensions")