コード例 #1
0
    def verify_callback(
            conn: SSL.Connection,
            x509: SSL.X509,
            errno: int,
            depth: int,
            is_cert_verified: bool
    ) -> bool:
        if is_cert_verified and depth == 0 and not sni:
            conn.cert_error = exceptions.InvalidCertificateException(
                f"Certificate verification error for {address}: Cannot validate hostname, SNI missing."
            )
            is_cert_verified = False
        elif is_cert_verified:
            pass
        else:
            conn.cert_error = exceptions.InvalidCertificateException(
                "Certificate verification error for {}: {} (errno: {}, depth: {})".format(
                    sni,
                    SSL._ffi.string(SSL._lib.X509_verify_cert_error_string(errno)).decode(),
                    errno,
                    depth
                )
            )

        # SSL_VERIFY_NONE: The handshake will be continued regardless of the verification result.
        return is_cert_verified
コード例 #2
0
    def verify_callback(
            conn: SSL.Connection,
            x509: SSL.X509,
            errno: int,
            depth: int,
            is_cert_verified: bool
    ) -> bool:
        if is_cert_verified and depth == 0:
            # Verify hostname of leaf certificate.
            cert = certs.Cert(x509)
            try:
                crt: typing.Dict[str, typing.Any] = dict(
                    subjectAltName=[("DNS", x.decode("ascii", "strict")) for x in cert.altnames]
                )
                if cert.cn:
                    crt["subject"] = [[["commonName", cert.cn.decode("ascii", "strict")]]]
                if sni:
                    # SNI hostnames allow support of IDN by using ASCII-Compatible Encoding
                    # Conversion algorithm is in RFC 3490 which is implemented by idna codec
                    # https://docs.python.org/3/library/codecs.html#text-encodings
                    # https://tools.ietf.org/html/rfc6066#section-3
                    # https://tools.ietf.org/html/rfc4985#section-3
                    hostname = sni.encode("idna").decode("ascii")
                else:
                    hostname = "no-hostname"
                match_hostname(crt, hostname)
            except (ValueError, CertificateError) as e:
                conn.cert_error = exceptions.InvalidCertificateException(
                    "Certificate verification error for {}: {}".format(
                        sni or repr(address),
                        str(e)
                    )
                )
                is_cert_verified = False
        elif is_cert_verified:
            pass
        else:
            conn.cert_error = exceptions.InvalidCertificateException(
                "Certificate verification error for {}: {} (errno: {}, depth: {})".format(
                    sni,
                    SSL._ffi.string(SSL._lib.X509_verify_cert_error_string(errno)).decode(),
                    errno,
                    depth
                )
            )

        # SSL_VERIFY_NONE: The handshake will be continued regardless of the verification result.
        return is_cert_verified
コード例 #3
0
 def verify_cert(conn, x509, errno, err_depth, is_cert_verified):
     if not is_cert_verified:
         self.ssl_verification_error = exceptions.InvalidCertificateException(
             "Certificate Verification Error for {}: {} (errno: {}, depth: {})"
             .format(
                 sni,
                 strutils.always_str(
                     SSL._ffi.string(
                         SSL._lib.X509_verify_cert_error_string(
                             errno)), "utf8"), errno, err_depth))
     return is_cert_verified
コード例 #4
0
    def convert_to_ssl(self, sni=None, alpn_protos=None, **sslctx_kwargs):
        """
            cert: Path to a file containing both client cert and private key.

            options: A bit field consisting of OpenSSL.SSL.OP_* values
            verify_options: A bit field consisting of OpenSSL.SSL.VERIFY_* values
            ca_path: Path to a directory of trusted CA certificates prepared using the c_rehash tool
            ca_pemfile: Path to a PEM formatted trusted CA certificate
        """
        verification_mode = sslctx_kwargs.get('verify_options', None)
        if verification_mode == SSL.VERIFY_PEER and not sni:
            raise exceptions.TlsException(
                "Cannot validate certificate hostname without SNI")

        context = self.create_ssl_context(alpn_protos=alpn_protos,
                                          sni=sni,
                                          **sslctx_kwargs)
        self.connection = SSL.Connection(context, self.connection)
        if sni:
            self.sni = sni
            self.connection.set_tlsext_host_name(sni.encode("idna"))
        self.connection.set_connect_state()
        try:
            self.connection.do_handshake()
        except SSL.Error as v:
            if self.ssl_verification_error:
                raise self.ssl_verification_error
            else:
                raise exceptions.TlsException("SSL handshake error: %s" %
                                              repr(v))

        self.cert = certs.SSLCert(self.connection.get_peer_certificate())

        # Keep all server certificates in a list
        for i in self.connection.get_peer_cert_chain():
            self.server_certs.append(certs.SSLCert(i))

        # Validate TLS Hostname
        try:
            crt = dict(subjectAltName=[("DNS", x.decode("ascii", "strict"))
                                       for x in self.cert.altnames])
            if self.cert.cn:
                crt["subject"] = [[[
                    "commonName",
                    self.cert.cn.decode("ascii", "strict")
                ]]]
            if sni:
                # SNI hostnames allow support of IDN by using ASCII-Compatible Encoding
                # Conversion algorithm is in RFC 3490 which is implemented by idna codec
                # https://docs.python.org/3/library/codecs.html#text-encodings
                # https://tools.ietf.org/html/rfc6066#section-3
                # https://tools.ietf.org/html/rfc4985#section-3
                hostname = sni.encode("idna").decode("ascii")
            else:
                hostname = "no-hostname"
            match_hostname(crt, hostname)
        except (ValueError, CertificateError) as e:
            self.ssl_verification_error = exceptions.InvalidCertificateException(
                "Certificate Verification Error for {}: {}".format(
                    sni or repr(self.address), str(e)))
            if verification_mode == SSL.VERIFY_PEER:
                raise self.ssl_verification_error

        self.ssl_established = True
        self.rfile.set_descriptor(self.connection)
        self.wfile.set_descriptor(self.connection)
コード例 #5
0
ファイル: tcp.py プロジェクト: xinglongbing/mitmproxy
    def convert_to_ssl(self, sni=None, alpn_protos=None, **sslctx_kwargs):
        """
            cert: Path to a file containing both client cert and private key.

            options: A bit field consisting of OpenSSL.SSL.OP_* values
            verify_options: A bit field consisting of OpenSSL.SSL.VERIFY_* values
            ca_path: Path to a directory of trusted CA certificates prepared using the c_rehash tool
            ca_pemfile: Path to a PEM formatted trusted CA certificate
        """
        verification_mode = sslctx_kwargs.get('verify_options', None)
        if verification_mode == SSL.VERIFY_PEER and not sni:
            raise exceptions.TlsException(
                "Cannot validate certificate hostname without SNI")

        context = self.create_ssl_context(alpn_protos=alpn_protos,
                                          sni=sni,
                                          **sslctx_kwargs)
        self.connection = SSL.Connection(context, self.connection)
        if sni:
            self.sni = sni
            self.connection.set_tlsext_host_name(sni.encode("idna"))
        self.connection.set_connect_state()
        try:
            self.connection.do_handshake()
        except SSL.Error as v:
            if self.ssl_verification_error:
                raise self.ssl_verification_error
            else:
                raise exceptions.TlsException("SSL handshake error: %s" %
                                              repr(v))
        else:
            # Fix for pre v1.0 OpenSSL, which doesn't throw an exception on
            # certificate validation failure
            if verification_mode == SSL.VERIFY_PEER and self.ssl_verification_error:
                raise self.ssl_verification_error

        self.cert = certs.SSLCert(self.connection.get_peer_certificate())

        # Keep all server certificates in a list
        for i in self.connection.get_peer_cert_chain():
            self.server_certs.append(certs.SSLCert(i))

        # Validate TLS Hostname
        try:
            crt = dict(subjectAltName=[("DNS", x.decode("ascii", "strict"))
                                       for x in self.cert.altnames])
            if self.cert.cn:
                crt["subject"] = [[[
                    "commonName",
                    self.cert.cn.decode("ascii", "strict")
                ]]]
            if sni:
                hostname = sni
            else:
                hostname = "no-hostname"
            match_hostname(crt, hostname)
        except (ValueError, CertificateError) as e:
            self.ssl_verification_error = exceptions.InvalidCertificateException(
                "Certificate Verification Error for {}: {}".format(
                    sni or repr(self.address), str(e)))
            if verification_mode == SSL.VERIFY_PEER:
                raise self.ssl_verification_error

        self.ssl_established = True
        self.rfile.set_descriptor(self.connection)
        self.wfile.set_descriptor(self.connection)