def parse_args(self, server="127.0.0.1", dport=4433, server_name=None, mycert=None, mykey=None, client_hello=None, version=None, data=None, **kargs): super(TLSClientAutomaton, self).parse_args(mycert=mycert, mykey=mykey, **kargs) tmp = socket.getaddrinfo(server, dport) self.remote_name = None try: if ':' in server: inet_pton(socket.AF_INET6, server) else: inet_pton(socket.AF_INET, server) except Exception: self.remote_name = socket.getfqdn(server) if self.remote_name != server: tmp = socket.getaddrinfo(self.remote_name, dport) if server_name: self.remote_name = server_name self.remote_family = tmp[0][0] self.remote_ip = tmp[0][4][0] self.remote_port = dport self.local_ip = None self.local_port = None self.socket = None self.client_hello = client_hello self.advertised_tls_version = None if version: v = _tls_version_options.get(version, None) if not v: self.vprint("Unrecognized TLS version option.") else: self.advertised_tls_version = v self.linebreak = False if isinstance(data, bytes): self.data_to_send = [data] elif isinstance(data, six.string_types): self.data_to_send = [bytes_encode(data)] elif isinstance(data, list): self.data_to_send = list(bytes_encode(d) for d in reversed(data)) else: self.data_to_send = []
def _tls_P_hash(secret, seed, req_len, hm): """ Provides the implementation of P_hash function defined in section 5 of RFC 4346 (and section 5 of RFC 5246). Two parameters have been added (hm and req_len): - secret : the key to be used. If RFC 4868 is to be believed, the length must match hm.key_len. Actually, python hmac takes care of formatting every key. - seed : the seed to be used. - req_len : the length of data to be generated by iterating the specific HMAC function (hm). This prevents multiple calls to the function. - hm : the hmac function class to use for iteration (either Hmac_MD5 or Hmac_SHA1 in TLS <= 1.1 or Hmac_SHA256 or Hmac_SHA384 in TLS 1.2) """ hash_len = hm.hash_alg.hash_len n = (req_len + hash_len - 1) // hash_len seed = bytes_encode(seed) res = b"" a = hm(secret).digest(seed) # A(1) while n > 0: res += hm(secret).digest(a + seed) a = hm(secret).digest(a) n -= 1 return res[:req_len]
def pcom_binary_checksum(command): n = 0 command = bytes_encode(command) for _, c in enumerate(command): c = c if isinstance(c, int) else ord(c) # python 2 fallback n += c if n == 0: return [0x00, 0x00] else: two_complement = hex(0x10000 - (n % 0x10000))[2:].zfill(4) return [int(two_complement[:2], 16), int(two_complement[2:], 16)]
def enc(cls, oid): oid = bytes_encode(oid) if oid: lst = [int(x) for x in oid.strip(b".").split(b".")] else: lst = list() if len(lst) >= 2: lst[1] += 40 * lst[0] del(lst[0]) s = b"".join(BER_num_enc(k) for k in lst) return chb(hash(cls.tag)) + BER_len_enc(len(s)) + s
def i2m(self, pkt, val): if not isinstance(val, bytes): val = bytes_encode(val) ret_string = b"" for i in range(0, len(val), 2): tmp = val[i:i + 2] if len(tmp) == 2: ret_string += chb(int(tmp[::-1], 16)) else: ret_string += chb(int(b"F" + tmp[:1], 16)) return ret_string
def inet_ntop(af, addr): """Convert an IP address from binary form into text representation.""" # Use inet_ntop if available addr = bytes_encode(addr) try: return socket.inet_ntop(af, addr) except AttributeError: try: return _INET_NTOP[af](addr) except KeyError: raise ValueError("unknown address family %d" % af)
def sign(self, M, t="pkcs", h="sha256", mgf=None, L=None): M = bytes_encode(M) mgf = mgf or padding.MGF1 h = _get_hash(h) pad = _get_padding(t, mgf, h, L) try: return self.key.sign(M, pad, h) except UnsupportedAlgorithm: if t != "pkcs" and h != "md5-sha1": raise UnsupportedAlgorithm("RSA signature with %s" % h) return self._legacy_sign_md5_sha1(M)
def enc(cls, s): # /!\ this is DER encoding (bit strings are only zero-bit padded) s = bytes_encode(s) if len(s) % 8 == 0: unused_bits = 0 else: unused_bits = 8 - len(s) % 8 s += b"0" * unused_bits s = b"".join(chb(int(b"".join(chb(y) for y in x), 2)) for x in zip(*[iter(s)] * 8)) s = chb(unused_bits) + s return chb(hash(cls.tag)) + BER_len_enc(len(s)) + s
def i2m(self, pkt, s): ret_s = b"" for text in s: text = bytes_encode(text) # The initial string must be split into a list of strings # prepended with theirs sizes. while len(text) >= 255: ret_s += b"\xff" + text[:255] text = text[255:] # The remaining string is less than 255 bytes long if len(text): ret_s += struct.pack("!B", len(text)) + text return ret_s
def i2m(self, pkt, x): if isinstance(x, str): return x s = b"" for o in x: if isinstance(o, tuple) and len(o) >= 2: name = o[0] lval = o[1:] if isinstance(name, int): onum, oval = name, b"".join(lval) elif name in DHCPRevOptions: onum, f = DHCPRevOptions[name] if f is not None: lval = (f.addfield(pkt, b"", f.any2i(pkt, val)) for val in lval) # noqa: E501 else: lval = (bytes_encode(x) for x in lval) oval = b"".join(lval) else: warning("Unknown field option %s", name) continue s += chb(onum) s += chb(len(oval)) s += oval elif (isinstance(o, str) and o in DHCPRevOptions and DHCPRevOptions[o][1] is None): s += chb(DHCPRevOptions[o][0]) elif isinstance(o, int): s += chb(o) + b"\0" elif isinstance(o, (str, bytes)): s += bytes_encode(o) else: warning("Malformed option %s", o) return s
def verify(self, M, S, t="pkcs", h="sha256", mgf=None, L=None): M = bytes_encode(M) mgf = mgf or padding.MGF1 h = _get_hash(h) pad = _get_padding(t, mgf, h, L) try: try: self.pubkey.verify(S, M, pad, h) except UnsupportedAlgorithm: if t != "pkcs" and h != "md5-sha1": raise UnsupportedAlgorithm("RSA verification with %s" % h) self._legacy_verify_md5_sha1(M, S) return True except InvalidSignature: return False
def _legacy_pkcs1_v1_5_encode_md5_sha1(M, emLen): """ Legacy method for PKCS1 v1.5 encoding with MD5-SHA1 hash. """ M = bytes_encode(M) md5_hash = hashes.Hash(_get_hash("md5"), backend=default_backend()) md5_hash.update(M) sha1_hash = hashes.Hash(_get_hash("sha1"), backend=default_backend()) sha1_hash.update(M) H = md5_hash.finalize() + sha1_hash.finalize() if emLen < 36 + 11: warning("pkcs_emsa_pkcs1_v1_5_encode: " "intended encoded message length too short") return None PS = b'\xff' * (emLen - 36 - 3) return b'\x00' + b'\x01' + PS + b'\x00' + H
def _legacy_sign_md5_sha1(self, M): M = bytes_encode(M) k = self._modulusLen // 8 EM = _legacy_pkcs1_v1_5_encode_md5_sha1(M, k) if EM is None: warning("Key._rsassa_pkcs1_v1_5_sign(): unable to encode") return None m = pkcs_os2ip(EM) n = self._modulus if isinstance(m, int) and six.PY2: m = long(m) # noqa: F821 if (six.PY2 and not isinstance(m, long)) or m > n - 1: # noqa: F821 warning("Key._rsaep() expects a long between 0 and n-1") return None privExp = self.key.private_numbers().d s = pow(m, privExp, n) return pkcs_i2osp(s, k)
def __call__(cls, obj_path, obj_max_size, pem_marker=None): # This enables transparent DER and PEM-encoded data imports. # Note that when importing a PEM file with multiple objects (like ECDSA # private keys output by openssl), it will concatenate every object in # order to create a 'der' attribute. When converting a 'multi' DER file # into a PEM file, though, the PEM attribute will not be valid, # because we do not try to identify the class of each object. error_msg = "Unable to import data" if obj_path is None: raise Exception(error_msg) obj_path = bytes_encode(obj_path) if (b'\x00' not in obj_path) and os.path.isfile(obj_path): _size = os.path.getsize(obj_path) if _size > obj_max_size: raise Exception(error_msg) try: f = open(obj_path, "rb") _raw = f.read() f.close() except Exception: raise Exception(error_msg) else: _raw = obj_path try: if b"-----BEGIN" in _raw: frmt = "PEM" pem = _raw der_list = split_pem(_raw) der = b''.join(map(pem2der, der_list)) else: frmt = "DER" der = _raw pem = "" if pem_marker is not None: pem = der2pem(_raw, pem_marker) # type identification may be needed for pem_marker # in such case, the pem attribute has to be updated except Exception: raise Exception(error_msg) p = _PKIObj(frmt, der, pem) return p
def open(self): """Open the TUN or TAP device.""" if not self.closed: return self.outs = self.ins = open( "/dev/net/tun" if LINUX else ("/dev/%s" % self.iface), "r+b", buffering=0 ) if LINUX: from fcntl import ioctl # TUNSETIFF = 0x400454ca # IFF_TUN = 0x0001 # IFF_TAP = 0x0002 # IFF_NO_PI = 0x1000 ioctl(self.ins, 0x400454ca, struct.pack( "16sH", bytes_encode(self.iface), 0x0001 if self.mode_tun else 0x1002, )) self.closed = False
def __setattr__(self, name, value): # type: (str, Any) -> None if name == "val_readable": if isinstance(value, (str, bytes)): val = "".join(binrepr(orb(x)).zfill(8) for x in value) else: warning("Invalid val: should be bytes") val = "<invalid val_readable>" object.__setattr__(self, "val", val) object.__setattr__(self, name, bytes_encode(value)) object.__setattr__(self, "unused_bits", 0) elif name == "val": value = plain_str(value) if isinstance(value, str): if any(c for c in value if c not in ["0", "1"]): warning( "Invalid operation: 'val' is not a valid bit string." ) # noqa: E501 return else: if len(value) % 8 == 0: unused_bits = 0 else: unused_bits = 8 - (len(value) % 8) padded_value = value + ("0" * unused_bits) bytes_arr = zip(*[iter(padded_value)] * 8) val_readable = b"".join( chb(int("".join(x), 2)) for x in bytes_arr) # noqa: E501 else: warning("Invalid val: should be str") val_readable = b"<invalid val>" unused_bits = 0 object.__setattr__(self, "val_readable", val_readable) object.__setattr__(self, name, value) object.__setattr__(self, "unused_bits", unused_bits) elif name == "unused_bits": warning("Invalid operation: unused_bits rewriting " "is not supported.") else: object.__setattr__(self, name, value)
def __setattr__(self, name, value): if isinstance(value, str): value = bytes_encode(value) if name == "val_readable": if isinstance(value, bytes): val = b"".join( binrepr(orb(x)).zfill(8).encode("utf8") for x in value) # noqa: E501 else: val = "<invalid val_readable>" super(ASN1_Object, self).__setattr__("val", val) super(ASN1_Object, self).__setattr__(name, value) super(ASN1_Object, self).__setattr__("unused_bits", 0) elif name == "val": if isinstance(value, bytes): if any(True for x in range(len(value)) if value[x:x + 1] not in [b"0", b"1"]): print("Invalid operation: 'val' is not a valid bit string." ) # noqa: E501 return else: if len(value) % 8 == 0: unused_bits = 0 else: unused_bits = 8 - (len(value) % 8) padded_value = value + (b"0" * unused_bits) bytes_arr = zip(*[(padded_value[i:i + 1] for i in range(len(padded_value)))] * 8) val_readable = b"".join( chb(int(b"".join(x), 2)) for x in bytes_arr) else: val_readable = "<invalid val>" unused_bits = 0 super(ASN1_Object, self).__setattr__("val_readable", val_readable) super(ASN1_Object, self).__setattr__(name, value) super(ASN1_Object, self).__setattr__("unused_bits", unused_bits) elif name == "unused_bits": print("Invalid operation: unused_bits rewriting is not supported.") else: super(ASN1_Object, self).__setattr__(name, value)
def i2m(self, pkt, s): if pkt.type == 1: # A if s: s = inet_pton(socket.AF_INET, s) elif pkt.type in [2, 3, 4, 5, 12]: # NS, MD, MF, CNAME, PTR s = DNSStrField("", "").i2m(None, s) elif pkt.type == 16: # TXT ret_s = b"" for text in s: text = bytes_encode(text) # The initial string must be split into a list of strings # prepended with theirs sizes. while len(text) >= 255: ret_s += b"\xff" + text[:255] text = text[255:] # The remaining string is less than 255 bytes long if len(text): ret_s += struct.pack("!B", len(text)) + text s = ret_s elif pkt.type == 28: # AAAA if s: s = inet_pton(socket.AF_INET6, s) return s
def _header_line(name, val): """Creates a HTTP header line""" # Python 3.4 doesn't support % on bytes return bytes_encode(name) + b": " + bytes_encode(val)
def __init__(self, iface=None, mode_tun=None, default_read_size=MTU, strip_packet_info=True, *args, **kwargs): self.iface = bytes_encode(conf.iface if iface is None else iface) self.mode_tun = mode_tun if self.mode_tun is None: if self.iface.startswith(b"tun"): self.mode_tun = True elif self.iface.startswith(b"tap"): self.mode_tun = False else: raise ValueError( "Could not determine interface type for %r; set " "`mode_tun` explicitly." % (self.iface, )) self.strip_packet_info = bool(strip_packet_info) # This is non-zero when there is some kernel-specific packet info. # We add this to any MTU value passed to recv(), and use it to # remove leading bytes when strip_packet_info=True. self.mtu_overhead = 0 # The TUN packet specification sends raw IP at us, and doesn't specify # which version. self.kernel_packet_class = IPv46 if self.mode_tun else Ether if LINUX: devname = b"/dev/net/tun" # Having an EtherType always helps on Linux, then we don't need # to use auto-detection of IP version. if self.mode_tun: self.kernel_packet_class = LinuxTunPacketInfo self.mtu_overhead = 4 # len(LinuxTunPacketInfo) else: warning("tap devices on Linux do not include packet info!") self.strip_packet_info = True if len(self.iface) > LINUX_IFNAMSIZ: warning("Linux interface names are limited to %d bytes, " "truncating!" % (LINUX_IFNAMSIZ, )) self.iface = self.iface[:LINUX_IFNAMSIZ] elif BSD: # also DARWIN if not (self.iface.startswith(b"tap") or self.iface.startswith(b"tun")): raise ValueError("Interface names must start with `tun` or " "`tap` on BSD and Darwin") devname = b"/dev/" + self.iface if not self.strip_packet_info: warning("tun/tap devices on BSD and Darwin never include " "packet info!") self.strip_packet_info = True else: raise NotImplementedError("TunTapInterface is not supported on " "this platform!") sock = open(devname, "r+b", buffering=0) if LINUX: if self.mode_tun: flags = LINUX_IFF_TUN else: # Linux can send us LinuxTunPacketInfo for TAP interfaces, but # the kernel sends the wrong information! # # Instead of type=1 (Ether), it sends that of the payload # (eg: 0x800 for IPv4 or 0x86dd for IPv6). # # tap interfaces always send Ether frames, which include a # type parameter for the IPv4/v6/etc. payload, so we set # IFF_NO_PI. flags = LINUX_IFF_TAP | LINUX_IFF_NO_PI tsetiff = raw( LinuxTunIfReq(ifrn_name=bytes_encode(self.iface), ifru_flags=flags)) ioctl(sock, LINUX_TUNSETIFF, tsetiff) self.closed = False self.default_read_size = default_read_size super(TunTapInterface, self).__init__(sock)
def parse_args(self, server="127.0.0.1", dport=4433, server_name=None, mycert=None, mykey=None, client_hello=None, version=None, data=None, ciphersuite=None, curve=None, **kargs): super(TLSClientAutomaton, self).parse_args(mycert=mycert, mykey=mykey, **kargs) tmp = socket.getaddrinfo(server, dport) self.remote_name = None try: if ':' in server: inet_pton(socket.AF_INET6, server) else: inet_pton(socket.AF_INET, server) except Exception: self.remote_name = socket.getfqdn(server) if self.remote_name != server: tmp = socket.getaddrinfo(self.remote_name, dport) if server_name: self.remote_name = server_name self.remote_family = tmp[0][0] self.remote_ip = tmp[0][4][0] self.remote_port = dport self.local_ip = None self.local_port = None self.socket = None if (isinstance(client_hello, TLSClientHello) or isinstance(client_hello, TLS13ClientHello)): self.client_hello = client_hello else: self.client_hello = None self.advertised_tls_version = None if version: v = _tls_version_options.get(version, None) if not v: self.vprint("Unrecognized TLS version option.") else: self.advertised_tls_version = v self.linebreak = False if isinstance(data, bytes): self.data_to_send = [data] elif isinstance(data, six.string_types): self.data_to_send = [bytes_encode(data)] elif isinstance(data, list): self.data_to_send = list(bytes_encode(d) for d in reversed(data)) else: self.data_to_send = [] self.curve = None if self.advertised_tls_version == 0x0304: self.ciphersuite = 0x1301 if ciphersuite is not None: cs = int(ciphersuite, 16) if cs in _tls_cipher_suites.keys(): self.ciphersuite = cs if conf.crypto_valid_advanced: # Default to x25519 if supported self.curve = 29 else: # Or secp256r1 otherwise self.curve = 23 if curve is not None: for (group_id, ng) in _tls_named_groups.items(): if ng == curve: if curve == "x25519": if conf.crypto_valid_advanced: self.curve = group_id else: self.curve = group_id
def i2m(self, pkt, s): if not isinstance(s, bytes): s = bytes_encode(s) s = b"".join(chb(len(x)) + x for x in s.split(b".")) return s
def __init__(self, key=None): if key is None: self.key = b"" else: self.key = bytes_encode(key)
def enc(cls, s): s = bytes_encode(s) # Be sure we are encoding bytes return chb(hash(cls.tag)) + BER_len_enc(len(s)) + s
def pcom_ascii_checksum(command): n = 0 command = bytes_encode(command) for _, c in enumerate(command): n += orb(c) return list(map(ord, hex(n % 256)[2:].zfill(2).upper()))
def __bytes__(self): return bytes_encode(self._fix())
def i2m(self, pkt, x): if x is None: return b"" return bytes_encode(x)
def digest(self, tbd): if self.key is None: raise HMACError tbd = bytes_encode(tbd) return hmac.new(self.key, tbd, self.hash_alg.hash_cls).digest()
def __init__(self, size, term): self.term = bytes_encode(term) super(RandTermString, self).__init__(size=size)
def enc(cls, _s): # type: (str) -> bytes s = bytes_encode(_s) # Be sure we are encoding bytes return chb(hash(cls.tag)) + BER_len_enc(len(s)) + s