예제 #1
0
    def process_task(self, target, command, args):

        OUT_FORMAT = '      {0:<35}{1}'.format

        sslConn = create_sslyze_connection(target, self._shared_settings)

        # Make sure OpenSSL was built with support for compression to avoid false negatives
        if 'zlib compression' not in sslConn.get_available_compression_methods():
            raise RuntimeError('OpenSSL was not built with support for zlib / compression. Did you build nassl yourself ?')

        try: # Perform the SSL handshake
            sslConn.connect()
            compName = sslConn.get_current_compression_method()
        except ClientAuthenticationError: # The server asked for a client cert
            compName = sslConn.get_current_compression_method()
        finally:
            sslConn.close()

        # Text output
        if compName:
            compTxt = 'Supported'
        else:
            compTxt = 'Disabled'

        cmdTitle = 'Compression'
        txtOutput = [self.PLUGIN_TITLE_FORMAT(cmdTitle)]
        txtOutput.append(OUT_FORMAT("DEFLATE Compression:", compTxt))

        # XML output
        xmlOutput = Element(command, title=cmdTitle)
        if compName:
            xmlNode = Element('compressionMethod', type="DEFLATE")
            xmlOutput.append(xmlNode)

        return PluginBase.PluginResult(txtOutput, xmlOutput)
예제 #2
0
    def process_task(self, target, command):
        """
        Connects to the target server and tries to get acceptable CAs for client cert
        """
        (_, _, _, ssl_version) = target
        ssl_conn = create_sslyze_connection(target, self._shared_settings, ssl_version)

        res = []
        try:  # Perform the SSL handshake
            ssl_conn.connect()

        except ClientCertificateRequested:  # The server asked for a client cert
            res = ssl_conn.get_client_CA_list()

        finally:
            ssl_conn.close()


        text_output = [self.PLUGIN_TITLE_FORMAT(self.CMD_TITLE)]
        if res:
            xml_output = Element(command, title=self.CMD_TITLE, isProvided="True")
            for ca in res:
                text_output.append(self.FIELD_FORMAT('', str(ca)))
                ca_xml = Element('ca')
                ca_xml.text = ca
                xml_output.append(ca_xml)
        else:
            xml_output = Element(command, title=self.CMD_TITLE, isProvided="False")

        return PluginBase.PluginResult(text_output, xml_output)
    def process_task(self, target, command, args):
        
        OUT_FORMAT = '        {0:<25} {1}'.format

        sslConn = create_sslyze_connection(target, self._shared_settings)

        try: # Perform the SSL handshake
            sslConn.connect()
            compName = sslConn.get_current_compression_name()
        except ClientAuthenticationError: # The server asked for a client cert
            compName = sslConn.get_current_compression_name()
        finally:
            sslConn.close()
      
        # Text output
        if compName:
            compTxt = 'Enabled ' +  compName
            compXml = {'isSupported':'True','type':compName.strip('()')}
        else:
            compTxt = 'Disabled'
            compXml = {'isSupported':'False'}
            
        cmdTitle = 'Compression'
        txtOutput = [self.PLUGIN_TITLE_FORMAT(cmdTitle)]
        txtOutput.append(OUT_FORMAT("Compression Support:", compTxt))

        # XML output
        xmlNode = Element('compression', compXml)
        xmlOutput = Element(command, title = cmdTitle)
        xmlOutput.append(xmlNode)

        return PluginBase.PluginResult(txtOutput, xmlOutput)
예제 #4
0
    def _test_ciphersuite(self, target, ssl_version, ssl_cipher):
        """
        Initiates a SSL handshake with the server, using the SSL version and
        cipher suite specified.
        """
        sslConn = create_sslyze_connection(target, self._shared_settings,
                                           ssl_version)
        sslConn.set_cipher_list(ssl_cipher)

        try:  # Perform the SSL handshake
            sslConn.connect()

        except SSLHandshakeRejected as e:
            return 'rejectedCipherSuites', ssl_cipher, None, None, str(e)

        except:
            raise

        else:
            ssl_cipher = sslConn.get_current_cipher_name()
            keysize = sslConn.get_current_cipher_bits()

            if 'ECDH' in ssl_cipher:
                dh_infos = sslConn.get_ecdh_param()
            elif 'DH' in ssl_cipher:
                dh_infos = sslConn.get_dh_param()
            else:
                dh_infos = None
            status_msg = sslConn.post_handshake_check()
            return 'acceptedCipherSuites', ssl_cipher, keysize, dh_infos, status_msg

        finally:
            sslConn.close()
예제 #5
0
    def _get_cert(self, target, storePath):
        """
        Connects to the target server and uses the supplied trust store to
        validate the server's certificate. Returns the server's certificate and
        OCSP response.
        """
        (_, _, _, sslVersion) = target
        sslConn = create_sslyze_connection(target, self._shared_settings, sslVersion, sslVerifyLocations=storePath)

        # Enable OCSP stapling
        sslConn.set_tlsext_status_ocsp()

        try:  # Perform the SSL handshake
            sslConn.connect()

            ocspResp = sslConn.get_tlsext_status_ocsp_resp()
            x509Cert = sslConn.get_peer_certificate()
            (_, verifyStr) = sslConn.get_certificate_chain_verify_result()

        except ClientCertificateRequested:  # The server asked for a client cert
            # We can get the server cert anyway
            ocspResp = sslConn.get_tlsext_status_ocsp_resp()
            x509Cert = sslConn.get_peer_certificate()
            (_, verifyStr) = sslConn.get_certificate_chain_verify_result()

        finally:
            sslConn.close()

        return (x509Cert, verifyStr, ocspResp)
예제 #6
0
파일: PluginHSTS.py 프로젝트: RuneTM/sslyze
    def _get_hsts_header(self, target):

        hstsHeader = None
        MAX_REDIRECT = 5
        nb_redirect = 0
        httpGetFormat = "GET {0} HTTP/1.0\r\nHost: {1}\r\n{2}Connection: close\r\n\r\n".format
        httpPath = "/"
        httpAppend = ""

        while nb_redirect < MAX_REDIRECT:
            sslConn = create_sslyze_connection(target, self._shared_settings)

            # Perform the SSL handshake
            sslConn.connect()

            sslConn.write(httpGetFormat(httpPath, target[0], httpAppend))
            httpResp = parse_http_response(sslConn.read(2048))
            sslConn.close()

            if httpResp.version == 9:
                # HTTP 0.9 => Probably not an HTTP response
                raise Exception("Server did not return an HTTP response")
            elif 300 <= httpResp.status < 400:
                redirectHeader = httpResp.getheader("Location", None)
                cookieHeader = httpResp.getheader("Set-Cookie", None)

                if redirectHeader is None:
                    break

                o = urlparse(redirectHeader)
                httpPath = o.path

                # Handle absolute redirection URL
                if o.hostname:
                    if o.port:
                        port = o.port
                    else:
                        if o.scheme == "https":
                            port = 443
                        elif o.scheme == "http":
                            # We would have to use urllib for http: URLs
                            raise Exception("Error: server sent a redirection to HTTP.")
                        else:
                            port = target[2]

                    target = (o.hostname, o.hostname, port, target[3])

                # Handle cookies
                if cookieHeader:
                    cookie = Cookie.SimpleCookie(cookieHeader)

                    if cookie:
                        httpAppend = "Cookie:" + cookie.output(attrs=[], header="", sep=";") + "\r\n"

                nb_redirect += 1
            else:
                hstsHeader = httpResp.getheader("strict-transport-security", None)
                break

        return hstsHeader
예제 #7
0
    def _pref_ciphersuite(self, target, ssl_version):
        """
        Initiates a SSL handshake with the server, using the SSL version and cipher
        suite specified.
        """
        sslConn = create_sslyze_connection(target, self._shared_settings,
                                           ssl_version)

        try:  # Perform the SSL handshake
            sslConn.connect()

            ssl_cipher = sslConn.get_cipher_name()
            if 'ADH' in ssl_cipher or 'AECDH' in ssl_cipher:
                keysize = 'Anon'  # Anonymous, let s not care about the key size
            else:
                keysize = str(sslConn.get_cipher_bits()) + ' bits'

            status_msg = sslConn.post_handshake_check()
            return ('preferredCipherSuite', ssl_cipher, keysize, status_msg)

        except:
            return None

        finally:
            sslConn.close()
예제 #8
0
    def _get_cert(self, target):
        """
        Connects to the target server and returns the server's certificate and
        OCSP response.
        """
        (host, ip, port, sslVersion) = target
        sslConn = create_sslyze_connection(target,
                                           self._shared_settings,
                                           sslVersion,
                                           sslVerifyLocations=MOZILLA_CA_STORE)

        # Enable OCSP stapling
        sslConn.set_tlsext_status_ocsp()

        try:  # Perform the SSL handshake
            sslConn.connect()

            ocspResp = sslConn.get_tlsext_status_ocsp_resp()
            x509Cert = sslConn.get_peer_certificate()
            (verifyCode,
             verifyStr) = sslConn.get_certificate_chain_verify_result()

        except ClientAuthenticationError:  # The server asked for a client cert
            # We can get the server cert anyway
            ocspResp = sslConn.get_tlsext_status_ocsp_resp()
            x509Cert = sslConn.get_peer_certificate()
            (verifyCode,
             verifyStr) = sslConn.get_certificate_chain_verify_result()

        finally:
            sslConn.close()

        return (x509Cert, verifyStr, ocspResp)
예제 #9
0
    def _get_cert(self, target, trustStoreList):
        """
        Connects to the target server and returns the server's certificate
        Also performs verification against multiple trust stores.
        """
        verifyResults = {}
        for trustStorePath in trustStoreList:
            
            (host, ip, port, sslVersion) = target
            sslConn = create_sslyze_connection(target, self._shared_settings, 
                                               sslVersion, 
                                               sslVerifyLocations=trustStorePath)
            
            try:
                # Perform the SSL handshake
                sslConn.connect()
                x509Cert = sslConn.get_peer_certificate()
                (verifyCode, verifyStr) = sslConn.get_certificate_chain_verify_result()
            
            except ClientCertificateError:
                # The server asked for a client cert
                # We can get the server cert anyway
                x509Cert = sslConn.get_peer_certificate()
                (verifyCode, verifyStr) = sslConn.get_certificate_chain_verify_result()          
            
            finally:
                sslConn.close()

            verifyResults[trustStorePath] = verifyStr

        return (x509Cert, verifyResults)
예제 #10
0
    def _get_cert(self, target):
        """
        Connects to the target server and returns the server's certificate and
        OCSP response.
        """
        (host, ip, port, sslVersion) = target
        sslConn = create_sslyze_connection(target, self._shared_settings, sslVersion, 
                                           sslVerifyLocations=MOZILLA_CA_STORE)
        
        # Enable OCSP stapling
        sslConn.set_tlsext_status_ocsp()
        
        try: # Perform the SSL handshake
            sslConn.connect()
            
            ocspResp = sslConn.get_tlsext_status_ocsp_resp()
            x509Cert = sslConn.get_peer_certificate()
            (verifyCode, verifyStr) = sslConn.get_certificate_chain_verify_result()
        
        except ClientAuthenticationError: # The server asked for a client cert
            # We can get the server cert anyway
            ocspResp = sslConn.get_tlsext_status_ocsp_resp()
            x509Cert = sslConn.get_peer_certificate()
            (verifyCode, verifyStr) = sslConn.get_certificate_chain_verify_result()      
            
        finally:
            sslConn.close()

        return (x509Cert, verifyStr, ocspResp)
예제 #11
0
    def _get_cert(self, target, trustStoreList):
        """
        Connects to the target server and returns the server's certificate
        Also performs verification against multiple trust stores.
        """
        verifyResults = {}
        for trustStorePath in trustStoreList:

            (host, ip, port, sslVersion) = target
            sslConn = create_sslyze_connection(
                target,
                self._shared_settings,
                sslVersion,
                sslVerifyLocations=trustStorePath)

            try:
                # Perform the SSL handshake
                sslConn.connect()
                x509Cert = sslConn.get_peer_certificate()
                (verifyCode,
                 verifyStr) = sslConn.get_certificate_chain_verify_result()

            except ClientCertificateError:
                # The server asked for a client cert
                # We can get the server cert anyway
                x509Cert = sslConn.get_peer_certificate()
                (verifyCode,
                 verifyStr) = sslConn.get_certificate_chain_verify_result()

            finally:
                sslConn.close()

            verifyResults[trustStorePath] = verifyStr

        return (x509Cert, verifyResults)
예제 #12
0
    def _get_cert(self, target, store_path):
        """
        Connects to the target server and uses the supplied trust store to
        validate the server's certificate. Returns the server's certificate and
        OCSP response.
        """
        (_, _, _, ssl_version) = target
        ssl_conn = create_sslyze_connection(target,
                                            self._shared_settings,
                                            ssl_version,
                                            sslVerifyLocations=store_path)

        # Enable OCSP stapling
        ssl_conn.set_tlsext_status_ocsp()

        try:  # Perform the SSL handshake
            ssl_conn.connect()

            ocsp_resp = ssl_conn.get_tlsext_status_ocsp_resp()
            x509_cert_chain = ssl_conn.get_peer_cert_chain()
            (_, verify_str) = ssl_conn.get_certificate_chain_verify_result()

        except ClientCertificateRequested:  # The server asked for a client cert
            # We can get the server cert anyway
            ocsp_resp = ssl_conn.get_tlsext_status_ocsp_resp()
            x509_cert_chain = ssl_conn.get_peer_cert_chain()
            (_, verify_str) = ssl_conn.get_certificate_chain_verify_result()

        finally:
            ssl_conn.close()

        return x509_cert_chain, verify_str, ocsp_resp
    def _test_ciphersuite(self, target, ssl_version, ssl_cipher):
        """
        Initiates a SSL handshake with the server, using the SSL version and
        cipher suite specified.
        """
        sslConn = create_sslyze_connection(target, self._shared_settings, ssl_version)
        sslConn.set_cipher_list(ssl_cipher)

        try: # Perform the SSL handshake
            sslConn.connect()

        except SSLHandshakeRejected as e:
            return 'rejectedCipherSuites', ssl_cipher, None, None, str(e)

        except:
            raise

        else:
            ssl_cipher = sslConn.get_current_cipher_name()
            keysize = sslConn.get_current_cipher_bits()
                
            if 'ECDH' in ssl_cipher :
                dh_infos = sslConn.get_ecdh_param()
            elif 'DH' in ssl_cipher :
                dh_infos = sslConn.get_dh_param()
            else :
                dh_infos = None
            status_msg = sslConn.post_handshake_check()
            return 'acceptedCipherSuites', ssl_cipher, keysize, dh_infos, status_msg

        finally:
            sslConn.close()
예제 #14
0
    def _pref_ciphersuite(self, target, ssl_version):
        """
        Initiates a SSL handshake with the server, using the SSL version and cipher
        suite specified.
        """
        sslConn = create_sslyze_connection(target, self._shared_settings,
                                           ssl_version)

        try:  # Perform the SSL handshake
            sslConn.connect()

            ssl_cipher = sslConn.get_current_cipher_name()
            keysize = sslConn.get_current_cipher_bits()

            if 'ECDH' in ssl_cipher:
                dh_infos = sslConn.get_ecdh_param()
            elif 'DH' in ssl_cipher:
                dh_infos = sslConn.get_dh_param()
            else:
                dh_infos = None

            status_msg = sslConn.post_handshake_check()
            return 'preferredCipherSuite', ssl_cipher, keysize, dh_infos, status_msg

        except:
            return None

        finally:
            sslConn.close()
    def _pref_ciphersuite(self, target, ssl_version):
        """
        Initiates a SSL handshake with the server, using the SSL version and cipher
        suite specified.
        """
        sslConn = create_sslyze_connection(target, self._shared_settings, ssl_version)

        try: # Perform the SSL handshake
            sslConn.connect()

            ssl_cipher = sslConn.get_current_cipher_name()
            keysize = sslConn.get_current_cipher_bits()

            if 'ECDH' in ssl_cipher :
                dh_infos = sslConn.get_ecdh_param()
            elif 'DH' in ssl_cipher :
                dh_infos = sslConn.get_dh_param()
            else :
                dh_infos = None

            status_msg = sslConn.post_handshake_check()
            return 'preferredCipherSuite', ssl_cipher, keysize,  dh_infos, status_msg

        except:
            return None

        finally:
            sslConn.close()
예제 #16
0
    def process_task(self, target, command, args):

        OUT_FORMAT = '        {0:<25} {1}'.format

        sslConn = create_sslyze_connection(target, self._shared_settings)

        try:  # Perform the SSL handshake
            sslConn.connect()
            compName = sslConn.get_current_compression_name()
        except ClientAuthenticationError:  # The server asked for a client cert
            compName = sslConn.get_current_compression_name()
        finally:
            sslConn.close()

        # Text output
        if compName:
            compTxt = 'Enabled ' + compName
            compXml = {'isSupported': 'True', 'type': compName.strip('()')}
        else:
            compTxt = 'Disabled'
            compXml = {'isSupported': 'False'}

        cmdTitle = 'Compression'
        txtOutput = [self.PLUGIN_TITLE_FORMAT(cmdTitle)]
        txtOutput.append(OUT_FORMAT("Compression Support:", compTxt))

        # XML output
        xmlNode = Element('compression', compXml)
        xmlOutput = Element(command, title=cmdTitle)
        xmlOutput.append(xmlNode)

        return PluginBase.PluginResult(txtOutput, xmlOutput)
예제 #17
0
    def _test_ciphersuite(self, target, ssl_version, ssl_cipher):
        """
        Initiates a SSL handshake with the server, using the SSL version and
        cipher suite specified.
        """
        sslConn = create_sslyze_connection(target, self._shared_settings, ssl_version)
        sslConn.set_cipher_list(ssl_cipher)

        try: # Perform the SSL handshake
            sslConn.connect()

        except SSLHandshakeRejected as e:
            return 'rejectedCipherSuites', ssl_cipher, None, str(e)

        except:
            raise

        else:
            ssl_cipher = sslConn.get_current_cipher_name()
            if 'ADH' in ssl_cipher or 'AECDH' in ssl_cipher:
                keysize = 'Anon' # Anonymous, let s not care about the key size
            else:
                keysize = str(sslConn.get_current_cipher_bits()) + ' bits'

            status_msg = sslConn.post_handshake_check()
            return 'acceptedCipherSuites', ssl_cipher, keysize, status_msg

        finally:
            sslConn.close()
예제 #18
0
    def process_task(self, target, command):
        """
        Connects to the target server and tries to get acceptable CAs for client cert
        """
        (_, _, _, ssl_version) = target
        ssl_conn = create_sslyze_connection(target, self._shared_settings,
                                            ssl_version)

        res = []
        try:  # Perform the SSL handshake
            ssl_conn.connect()

        except ClientCertificateRequested:  # The server asked for a client cert
            res = ssl_conn.get_client_CA_list()

        finally:
            ssl_conn.close()

        text_output = [self.PLUGIN_TITLE_FORMAT(self.CMD_TITLE)]
        if res:
            xml_output = Element(command,
                                 title=self.CMD_TITLE,
                                 isProvided="True")
            for ca in res:
                text_output.append(self.FIELD_FORMAT('', str(ca)))
                ca_xml = Element('ca')
                ca_xml.text = ca
                xml_output.append(ca_xml)
        else:
            xml_output = Element(command,
                                 title=self.CMD_TITLE,
                                 isProvided="False")

        return PluginBase.PluginResult(text_output, xml_output)
    def _pref_ciphersuite(self, target, ssl_version):
        """
        Initiates a SSL handshake with the server, using the SSL version and cipher
        suite specified.
        """
        sslConn = create_sslyze_connection(target, self._shared_settings,
                                           ssl_version)

        # logging.debug("call _pref_ciphersuite(%s, %s)"%(target, ssl_version))
        # Do not count -> nur Connections fuer accepted /rejected
        # self.log_connection_counter += 0

        try:  # Perform the SSL handshake
            sslConn.connect()

            ssl_cipher = sslConn.get_current_cipher_name()
            keysize = sslConn.get_current_cipher_bits()

            if 'ECDH' in ssl_cipher:
                dh_infos = sslConn.get_ecdh_param()
            elif 'DH' in ssl_cipher:
                dh_infos = sslConn.get_dh_param()
            else:
                dh_infos = None

            status_msg = sslConn.post_handshake_check()
            return [('preferredCipherSuite', ssl_cipher, keysize, dh_infos,
                     status_msg)]

        except:
            return []

        finally:
            sslConn.close()
예제 #20
0
    def process_task(self, target, command, args):

        OUT_FORMAT = '      {0:<35}{1}'.format
        (host, ip, port, sslVersion) = target

        if sslVersion == SSLV23: # Could not determine the preferred  SSL version - client cert was required ?
            sslVersion = TLSV1 # Default to TLS 1.0
            target = (host, ip, port, sslVersion)

        sslConn = create_sslyze_connection(target, self._shared_settings)
        sslConn.sslVersion = sslVersion # Needed by the heartbleed payload

        # Awful hack #1: replace nassl.sslClient.do_handshake() with a heartbleed
        # checking SSL handshake so that all the SSLyze options
        # (startTLS, proxy, etc.) still work
        sslConn.do_handshake = new.instancemethod(do_handshake_with_heartbleed, sslConn, None)

        heartbleed = None
        try: # Perform the SSL handshake
            sslConn.connect()
        except HeartbleedSent:
            # Awful hack #2: directly read the underlying network socket
            heartbleed = sslConn._sock.recv(16381)
        finally:
            sslConn.close()

        # Text output
        if heartbleed is None:
            raise Exception("Error: connection failed.")
        elif '\x01\x01\x01\x01\x01\x01\x01\x01\x01' in heartbleed:
            # Server replied with our hearbeat payload
            heartbleedTxt = 'VULNERABLE - Server is vulnerable to Heartbleed'
            heartbleedXml = 'True'
        else:
            heartbleedTxt = 'OK - Not vulnerable to Heartbleed'
            heartbleedXml = 'False'

        cmdTitle = 'OpenSSL Heartbleed'
        txtOutput = [self.PLUGIN_TITLE_FORMAT(cmdTitle)]
        txtOutput.append(OUT_FORMAT(heartbleedTxt, ""))

        # XML output
        xmlOutput = Element(command, title=cmdTitle)
        if heartbleed:
            xmlNode = Element('heartbleed', isVulnerable=heartbleedXml)
            xmlOutput.append(xmlNode)

        return PluginBase.PluginResult(txtOutput, xmlOutput)
예제 #21
0
    def process_task(self, target, command, args):

        OUT_FORMAT = '      {0:<35}{1}'.format
        (host, ip, port, sslVersion) = target

        if sslVersion == SSLV23: # Could not determine the preferred  SSL version - client cert was required ?
            sslVersion = TLSV1 # Default to TLS 1.0
            target = (host, ip, port, sslVersion)

        sslConn = create_sslyze_connection(target, self._shared_settings)
        sslConn.sslVersion = sslVersion # Needed by the heartbleed payload

        # Awful hack #1: replace nassl.sslClient.do_handshake() with a heartbleed
        # checking SSL handshake so that all the SSLyze options
        # (startTLS, proxy, etc.) still work
        sslConn.do_handshake = new.instancemethod(do_handshake_with_heartbleed, sslConn, None)

        heartbleed = None
        try: # Perform the SSL handshake
            sslConn.connect()
        except HeartbleedSent:
            # Awful hack #2: directly read the underlying network socket
            heartbleed = sslConn._sock.recv(16381)
        finally:
            sslConn.close()

        # Text output
        if heartbleed is None:
            raise Exception("Error: connection failed.")
        elif '\x01\x01\x01\x01\x01\x01\x01\x01\x01' in heartbleed:
            # Server replied with our hearbeat payload
            heartbleedTxt = 'VULNERABLE'
            heartbleedXml = 'True'
        else:
            heartbleedTxt = 'NOT vulnerable'
            heartbleedXml = 'False'

        cmdTitle = 'Heartbleed'
        txtOutput = [self.PLUGIN_TITLE_FORMAT(cmdTitle)]
        txtOutput.append(OUT_FORMAT("OpenSSL Heartbleed:", heartbleedTxt))

        # XML output
        xmlOutput = Element(command, title=cmdTitle)
        if heartbleed:
            xmlNode = Element('heartbleed', isVulnerable=heartbleedXml)
            xmlOutput.append(xmlNode)

        return PluginBase.PluginResult(txtOutput, xmlOutput)
    def _test_renegotiation(self, target):
        """
        Checks whether the server honors session renegotiation requests and
        whether it supports secure renegotiation.
        """
        sslConn = create_sslyze_connection(target, self._shared_settings)

        try: # Perform the SSL handshake
            sslConn.connect()
            secureReneg = sslConn.get_secure_renegotiation_support()

            try: # Let's try to renegotiate
                sslConn.do_renegotiate()
                clientReneg = True

            # Errors caused by a server rejecting the renegotiation
            except socket.error as e:
                if 'connection was forcibly closed' in str(e.args):
                    clientReneg = False
                elif 'reset by peer' in str(e.args):
                    clientReneg = False
                else:
                    raise
            #except socket.timeout as e:
            #    result_reneg = 'Rejected (timeout)'
            except OpenSSLError as e:
                if 'handshake failure' in str(e.args):
                    clientReneg = False
                elif 'no renegotiation' in str(e.args):
                    clientReneg = False
                elif 'tlsv1 unrecognized name' in str(e.args):
                    # Yahoo's very own way of rejecting a renegotiation
                    clientReneg = False
                else:
                    raise

            # Should be last as socket errors are also IOError
            except IOError as e:
                if 'Nassl SSL handshake failed' in str(e.args):
                    clientReneg = False
                else:
                    raise

        finally:
            sslConn.close()

        return (clientReneg, secureReneg)
예제 #23
0
    def _test_renegotiation(self, target):
        """
        Checks whether the server honors session renegotiation requests and
        whether it supports secure renegotiation.
        """
        sslConn = create_sslyze_connection(target, self._shared_settings)

        try:  # Perform the SSL handshake
            sslConn.connect()
            secureReneg = sslConn.get_secure_renegotiation_support()

            try:  # Let's try to renegotiate
                sslConn.do_renegotiate()
                clientReneg = True

            # Errors caused by a server rejecting the renegotiation
            except socket.error as e:
                if 'connection was forcibly closed' in str(e.args):
                    clientReneg = False
                elif 'reset by peer' in str(e.args):
                    clientReneg = False
                else:
                    raise
            #except socket.timeout as e:
            #    result_reneg = 'Rejected (timeout)'
            except OpenSSLError as e:
                if 'handshake failure' in str(e.args):
                    clientReneg = False
                elif 'no renegotiation' in str(e.args):
                    clientReneg = False
                elif 'tlsv1 unrecognized name' in str(e.args):
                    # Yahoo's very own way of rejecting a renegotiation
                    clientReneg = False
                else:
                    raise

            # Should be last as socket errors are also IOError
            except IOError as e:
                if 'Nassl SSL handshake failed' in str(e.args):
                    clientReneg = False
                else:
                    raise

        finally:
            sslConn.close()

        return (clientReneg, secureReneg)
예제 #24
0
    def _get_hsts_header(self, target):

        hstsHeader = None
        HTTP_GET_REQ = 'GET / HTTP/1.0\r\nHost: {0}\r\nConnection: close\r\n\r\n'.format(target[0])
        sslConn = create_sslyze_connection(target, self._shared_settings)

        # Perform the SSL handshake
        sslConn.connect()

        sslConn.write(HTTP_GET_REQ)
        httpResp = parse_http_response(sslConn.read(2048))
        sslConn.close()
        if httpResp.version == 9 :
            # HTTP 0.9 => Probably not an HTTP response
            raise Exception('Server did not return an HTTP response')
        else:
            hstsHeader = httpResp.getheader('strict-transport-security', None)
        return hstsHeader
예제 #25
0
    def _get_hsts_header(self, target):

        hstsHeader = None
        HTTP_GET_REQ = 'GET / HTTP/1.0\r\nHost: {0}\r\nConnection: close\r\n\r\n'.format(
            target[0])
        sslConn = create_sslyze_connection(target, self._shared_settings)

        # Perform the SSL handshake
        sslConn.connect()

        sslConn.write(HTTP_GET_REQ)
        httpResp = parse_http_response(sslConn.read(2048))
        sslConn.close()
        if httpResp.version == 9:
            # HTTP 0.9 => Probably not an HTTP response
            raise Exception('Server did not return an HTTP response')
        else:
            hstsHeader = httpResp.getheader('strict-transport-security', None)
        return hstsHeader
    def _test_ciphersuite(self, target, ssl_version, ssl_cipher, cipher_dict):
        """
        Initiates a SSL handshake with the server, using the SSL version and
        cipher suite specified.
        """
        sslConn = create_sslyze_connection(target, self._shared_settings,
                                           ssl_version)
        sslConn.set_cipher_list(ssl_cipher)

        try:  # Perform the SSL handshake
            sslConn.connect()

        except SSLHandshakeRejected as e:
            return 'rejectedCipherSuites', ssl_cipher, None, None, str(e)

        except:
            raise

        else:
            ssl_cipher = sslConn.get_current_cipher_name()
            keysize = sslConn.get_current_cipher_bits()

            if 'ECDH' in ssl_cipher:
                dh_infos = sslConn.get_ecdh_param()
            elif 'DH' in ssl_cipher:
                dh_infos = sslConn.get_dh_param()
            else:
                dh_infos = None
            status_msg = sslConn.post_handshake_check()

            # append *WEAK* if cipher is known to be vulnerable
            if ssl_cipher not in cipher_dict.get('whitelist'):
                for item in cipher_dict.get('blacklist'):
                    if item in ssl_cipher:
                        ssl_cipher += ' *WEAK*'
                        break
                if '*WEAK*' not in ssl_cipher:
                    ssl_cipher += ' (~Possibly Vulnerable~)'

            return 'acceptedCipherSuites', ssl_cipher, keysize, dh_infos, status_msg

        finally:
            sslConn.close()
    def _test_ciphersuite(self, target, ssl_version, ssl_ciphers):
        """
        Initiates a SSL handshake with the server, using the SSL version and
        cipher suite specified.
        """

        # logging.debug("call _test_ciphersuite(%s, %s, %s)"%(target, ssl_version, ssl_ciphers))
        self.log_connection_counter += 1

        sslConn = create_sslyze_connection(target, self._shared_settings,
                                           ssl_version)
        sslConn.set_cipher_list(":".join(ssl_ciphers))

        try:  # Perform the SSL handshake
            sslConn.connect()

        except SSLHandshakeRejected as e:
            # if the ciphers are rejected it can be a multi result
            # logging.debug("   rejected %s" % ssl_ciphers)
            return [('rejectedCipherSuites', ssl_cipher, None, None, str(e))
                    for ssl_cipher in ssl_ciphers]

        except:
            raise

        else:
            ssl_cipher = sslConn.get_current_cipher_name()
            keysize = sslConn.get_current_cipher_bits()

            if 'ECDH' in ssl_cipher:
                dh_infos = sslConn.get_ecdh_param()
            elif 'DH' in ssl_cipher:
                dh_infos = sslConn.get_dh_param()
            else:
                dh_infos = None
            status_msg = sslConn.post_handshake_check()
            # if the cipher is accepted it is for sure a single result
            # logging.debug("   accepted %s in %s" % (ssl_cipher, ssl_ciphers))
            return [('acceptedCipherSuites', ssl_cipher, keysize, dh_infos,
                     status_msg)]

        finally:
            sslConn.close()
    def _test_ciphersuite(self, target, ssl_version, ssl_cipher, cipher_dict):
        """
        Initiates a SSL handshake with the server, using the SSL version and
        cipher suite specified.
        """
        sslConn = create_sslyze_connection(target, self._shared_settings, ssl_version)
        sslConn.set_cipher_list(ssl_cipher)

        try:  # Perform the SSL handshake
            sslConn.connect()

        except SSLHandshakeRejected as e:
            return "rejectedCipherSuites", ssl_cipher, None, None, str(e)

        except:
            raise

        else:
            ssl_cipher = sslConn.get_current_cipher_name()
            keysize = sslConn.get_current_cipher_bits()

            if "ECDH" in ssl_cipher:
                dh_infos = sslConn.get_ecdh_param()
            elif "DH" in ssl_cipher:
                dh_infos = sslConn.get_dh_param()
            else:
                dh_infos = None
            status_msg = sslConn.post_handshake_check()

            # append *WEAK* if cipher is known to be vulnerable
            if ssl_cipher not in cipher_dict.get("whitelist"):
                for item in cipher_dict.get("blacklist"):
                    if item in ssl_cipher:
                        ssl_cipher += " *WEAK*"
                        break
                if "*WEAK*" not in ssl_cipher:
                    ssl_cipher += " (~Possibly Vulnerable~)"

            return "acceptedCipherSuites", ssl_cipher, keysize, dh_infos, status_msg

        finally:
            sslConn.close()
예제 #29
0
    def process_task(self, target, command, args):

        OUT_FORMAT = '      {0:<35}{1}'.format

        sslConn = create_sslyze_connection(target, self._shared_settings)

        # Make sure OpenSSL was built with support for compression to avoid false negatives
        if 'zlib compression' not in sslConn.get_available_compression_methods(
        ):
            raise RuntimeError(
                'OpenSSL was not built with support for zlib / compression. Did you build nassl yourself ?'
            )

        try:  # Perform the SSL handshake
            sslConn.connect()
            compName = sslConn.get_current_compression_method()
        except ClientCertificateRequested:  # The server asked for a client cert
            compName = sslConn.get_current_compression_method()
        finally:
            sslConn.close()

        # Text output
        if compName:
            compTxt = 'Supported'
        else:
            compTxt = 'Disabled'

        cmdTitle = 'Compression'
        txtOutput = [self.PLUGIN_TITLE_FORMAT(cmdTitle)]
        txtOutput.append(OUT_FORMAT("DEFLATE Compression:", compTxt))

        # XML output
        xmlOutput = Element(command, title=cmdTitle)
        if compName:
            xmlNode = Element('compressionMethod', type="DEFLATE")
            xmlOutput.append(xmlNode)

        return PluginBase.PluginResult(txtOutput, xmlOutput)
예제 #30
0
    def _resume_ssl_session(self, target, sslSession=None, tlsTicket=False):
        """
        Connect to the server and returns the session object that was assigned
        for that connection.
        If ssl_session is given, tries to resume that session.
        """
        sslConn = create_sslyze_connection(target, self._shared_settings)
        if not tlsTicket:
        # Need to disable TLS tickets to test session IDs, according to rfc5077:
        # If a ticket is presented by the client, the server MUST NOT attempt
        # to use the Session ID in the ClientHello for stateful session resumption
            sslConn.set_options(SSL_OP_NO_TICKET) # Turning off TLS tickets.

        if sslSession:
            sslConn.set_session(sslSession)

        try: # Perform the SSL handshake
            sslConn.connect()
            newSession = sslConn.get_session() # Get session data
        finally:
            sslConn.close()

        return newSession
예제 #31
0
    def _resume_ssl_session(self, target, sslSession=None, tlsTicket=False):
        """
        Connect to the server and returns the session object that was assigned
        for that connection.
        If ssl_session is given, tries to resume that session.
        """
        sslConn = create_sslyze_connection(target, self._shared_settings)
        if not tlsTicket:
            # Need to disable TLS tickets to test session IDs, according to rfc5077:
            # If a ticket is presented by the client, the server MUST NOT attempt
            # to use the Session ID in the ClientHello for stateful session resumption
            sslConn.set_options(SSL_OP_NO_TICKET)  # Turning off TLS tickets.

        if sslSession:
            sslConn.set_session(sslSession)

        try:  # Perform the SSL handshake
            sslConn.connect()
            newSession = sslConn.get_session()  # Get session data
        finally:
            sslConn.close()

        return newSession
예제 #32
0
    def process_task(self, target, command, args):

        sslConn = create_sslyze_connection(target, self._shared_settings)

        # Make sure OpenSSL was built with support for compression to avoid false negatives
        if 'zlib compression' not in sslConn.get_available_compression_methods():
            raise RuntimeError('OpenSSL was not built with support for zlib / compression. Did you build nassl yourself ?')

        try: # Perform the SSL handshake
            sslConn.connect()
            compName = sslConn.get_current_compression_method()
        except ClientCertificateRequested: # The server asked for a client cert
            compName = sslConn.get_current_compression_method()
        finally:
            sslConn.close()

        # Text output
        if compName:
            compTxt = 'VULNERABLE - Server supports Deflate compression'
        else:
            compTxt = 'OK - Compression disabled'

        cmdTitle = 'Deflate Compression'
        txtOutput = [self.PLUGIN_TITLE_FORMAT(cmdTitle)]
        txtOutput.append(self.FIELD_FORMAT(compTxt, ""))

        # XML output
        xmlOutput = Element(command, title=cmdTitle)
        if compName:
            xmlNode = Element('compressionMethod', type="DEFLATE", isSupported="True")
            xmlOutput.append(xmlNode)
        else:
            xmlNode = Element('compressionMethod', type="DEFLATE", isSupported="False")
            xmlOutput.append(xmlNode)

        return PluginBase.PluginResult(txtOutput, xmlOutput)
예제 #33
0
    def _pref_ciphersuite(self, target, ssl_version):
        """
        Initiates a SSL handshake with the server, using the SSL version and cipher
        suite specified.
        """
        sslConn = create_sslyze_connection(target, self._shared_settings, ssl_version)
        
        try: # Perform the SSL handshake
            sslConn.connect()

            ssl_cipher = sslConn.get_cipher_name()
            if 'ADH' in ssl_cipher or 'AECDH' in ssl_cipher:
                keysize = 'Anon' # Anonymous, let s not care about the key size
            else:
                keysize = str(sslConn.get_cipher_bits())+' bits'
                
            status_msg = sslConn.post_handshake_check()
            return ('preferredCipherSuite', ssl_cipher, keysize, status_msg)
        
        except:
            return None
    
        finally:
            sslConn.close()
예제 #34
0
파일: PluginHSTS.py 프로젝트: 0x0mar/sslyze
    def _get_hsts_header(self, target):

        hstsHeader = None
        MAX_REDIRECT = 5
        nb_redirect = 0
        httpGetFormat = 'GET {0} HTTP/1.0\r\nHost: {1}\r\n{2}Connection: close\r\n\r\n'.format
        httpPath = '/'
        httpAppend = ''
        
        while nb_redirect < MAX_REDIRECT:
            sslConn = create_sslyze_connection(target, self._shared_settings)
            
            # Perform the SSL handshake
            sslConn.connect()
            
            sslConn.write(httpGetFormat(httpPath, target[0], httpAppend))
            httpResp = parse_http_response(sslConn.read(2048))
            sslConn.close()
            
            if httpResp.version == 9 :
                # HTTP 0.9 => Probably not an HTTP response
                raise Exception('Server did not return an HTTP response')
            else:
                hstsHeader = httpResp.getheader('strict-transport-security', None)


            # If there was no HSTS header, check if the server returned a redirection
            if hstsHeader is None and 300 <= httpResp.status < 400:
                redirectHeader = httpResp.getheader('Location', None)
                cookieHeader = httpResp.getheader('Set-Cookie', None)
                
                if redirectHeader is None:
                    break
                
                o = urlparse(redirectHeader)
                httpPath = o.path
                
                # Handle absolute redirection URL
                if o.hostname:
                    if o.port:
                        port = o.port
                    else:
                        if o.scheme == 'https':
                            port = 443
                        elif o.scheme == 'http':
                            # We would have to use urllib for http: URLs
                            raise Exception("Error: server sent a redirection to HTTP.")
                        else:
                            port = target[2]
                        
                    target = (o.hostname, o.hostname, port, target[3])

                # Handle cookies
                if cookieHeader:
                    cookie = Cookie.SimpleCookie(cookieHeader)

                    if cookie:
                        httpAppend = 'Cookie:' + cookie.output(attrs=[], header='', sep=';') + '\r\n'

                nb_redirect+=1
            else:
                # If the server did not return a redirection just give up
                break

        
        return hstsHeader
    def process_task(self, target, command, arg):

        (_, _, _, sslVersion) = target

        # Get the server's cert chain
        sslConn = create_sslyze_connection(target, self._shared_settings, sslVersion)
        try: # Perform the SSL handshake
            sslConn.connect()
            certChain = sslConn.get_peer_cert_chain()
        except ClientCertificateRequested: # The server asked for a client cert
            # We can get the server cert chain anyway
            certChain = sslConn.get_peer_cert_chain()
        finally:
            sslConn.close()

        outputXml = Element(command, title = self.CMD_TITLE)
        outputTxt = [self.PLUGIN_TITLE_FORMAT(self.CMD_TITLE)]

        # Is this cert chain affected ?
        leafNotAfter = datetime.datetime.strptime(certChain[0].as_dict()['validity']['notAfter'], "%b %d %H:%M:%S %Y %Z")
        if leafNotAfter.year < 2016:
            # Not affected - the certificate expires before 2016
            outputTxt.append(self.FIELD_FORMAT('OK - Leaf certificate expires before 2016.', ''))
            outputXml.append(Element('chromeSha1Deprecation', isServerAffected = str(False)))

        else:
            certsWithSha1 = []
            for cert in certChain:
                if self._is_root_cert(cert):
                    # Ignore root certs as they are unaffected
                    continue

                if "sha1" in cert.as_dict()['signatureAlgorithm']:
                    certsWithSha1.append(cert)

            if certsWithSha1 == []:
                # Not affected - no certificates used SHA-1 in the chain
                outputTxt.append(self.FIELD_FORMAT('OK - Certificate chain does not contain any SHA-1 certificate.', ''))
                outputXml.append(Element('chromeSha1Deprecation', isServerAffected = str(False)))

            else:
                # Server is affected
                leafCertNotAfter = certChain[0].as_dict()['validity']['notAfter']
                outputXml2 = Element('chromeSha1Deprecation', isServerAffected = str(True),
                                     leafCertificateNotAfter = leafCertNotAfter)
                chrome39Txt = 'OK'
                chrome40Txt = 'OK'

                if leafNotAfter.year == 2016 and leafNotAfter.month < 6:
                    chrome41Txt = self.CHROME_MINOR_ERROR_TXT


                elif leafNotAfter.year == 2016 and leafNotAfter.month >= 6:
                    chrome40Txt = self.CHROME_MINOR_ERROR_TXT
                    chrome41Txt = self.CHROME_MINOR_ERROR_TXT

                else:
                    # Certificate expires in 2017
                    chrome39Txt = self.CHROME_MINOR_ERROR_TXT
                    chrome40Txt = self.CHROME_NEUTRAL_TXT
                    chrome41Txt = self.CHROME_INSECURE_TXT

                # Text output
                certsWithSha1Txt = ['"{0}"'.format(PluginCertInfo._extract_subject_CN_or_OUN(cert)) for cert in certsWithSha1]
                outputTxt.append(self.FIELD_FORMAT("Chrome 39 behavior:", chrome39Txt))
                outputTxt.append(self.FIELD_FORMAT("Chrome 40 behavior:", chrome40Txt))
                outputTxt.append(self.FIELD_FORMAT("Chrome 41 behavior:", chrome41Txt))
                outputTxt.append(self.FIELD_FORMAT("Leaf certificate notAfter field:", leafCertNotAfter))
                outputTxt.append(self.FIELD_FORMAT("SHA1-signed certificates:", certsWithSha1Txt))

                # XML output
                affectedCertsXml = Element('sha1SignedCertificates')
                for cert in certsWithSha1:
                    affectedCertsXml.append(PluginCertInfo._format_cert_to_xml(cert, '', self._shared_settings['sni']))
                outputXml2.append(affectedCertsXml)

                outputXml2.append(Element(
                    'chrome39',
                    behavior = chrome39Txt,
                    isAffected = str(False) if chrome39Txt is 'OK' else str(True)))
                outputXml2.append(Element(
                    'chrome40',
                    behavior = chrome40Txt,
                    isAffected = str(False) if chrome40Txt is 'OK' else str(True)))
                outputXml2.append(Element(
                    'chrome41',
                    behavior = chrome41Txt,
                    isAffected = str(True)))
                outputXml.append(outputXml2)
        
        return PluginBase.PluginResult(outputTxt, outputXml)
    def process_task(self, target, command, arg):

        (_, _, _, sslVersion) = target

        # Get the server's cert chain
        sslConn = create_sslyze_connection(target, self._shared_settings,
                                           sslVersion)
        try:  # Perform the SSL handshake
            sslConn.connect()
            certChain = sslConn.get_peer_cert_chain()
        except ClientCertificateRequested:  # The server asked for a client cert
            # We can get the server cert chain anyway
            certChain = sslConn.get_peer_cert_chain()
        finally:
            sslConn.close()

        outputXml = Element(command, title=self.CMD_TITLE)
        outputTxt = [self.PLUGIN_TITLE_FORMAT(self.CMD_TITLE)]

        # Is this cert chain affected ?
        leafNotAfter = datetime.datetime.strptime(
            certChain[0].as_dict()['validity']['notAfter'],
            "%b %d %H:%M:%S %Y %Z")
        if leafNotAfter.year < 2016:
            # Not affected - the certificate expires before 2016
            outputTxt.append(
                self.FIELD_FORMAT('OK - Leaf certificate expires before 2016.',
                                  ''))
            outputXml.append(
                Element('chromeSha1Deprecation', isServerAffected=str(False)))

        else:
            certsWithSha1 = []
            for cert in certChain:
                if self._is_root_cert(cert):
                    # Ignore root certs as they are unaffected
                    continue

                if "sha1" in cert.as_dict()['signatureAlgorithm']:
                    certsWithSha1.append(cert)

            if certsWithSha1 == []:
                # Not affected - no certificates used SHA-1 in the chain
                outputTxt.append(
                    self.FIELD_FORMAT(
                        'OK - Certificate chain does not contain any SHA-1 certificate.',
                        ''))
                outputXml.append(
                    Element('chromeSha1Deprecation',
                            isServerAffected=str(False)))

            else:
                # Server is affected
                leafCertNotAfter = certChain[0].as_dict(
                )['validity']['notAfter']
                outputXml2 = Element('chromeSha1Deprecation',
                                     isServerAffected=str(True),
                                     leafCertificateNotAfter=leafCertNotAfter)
                chrome39Txt = 'OK'
                chrome40Txt = 'OK'

                if leafNotAfter.year == 2016 and leafNotAfter.month < 6:
                    chrome41Txt = self.CHROME_MINOR_ERROR_TXT

                elif leafNotAfter.year == 2016 and leafNotAfter.month >= 6:
                    chrome40Txt = self.CHROME_MINOR_ERROR_TXT
                    chrome41Txt = self.CHROME_MINOR_ERROR_TXT

                else:
                    # Certificate expires in 2017
                    chrome39Txt = self.CHROME_MINOR_ERROR_TXT
                    chrome40Txt = self.CHROME_NEUTRAL_TXT
                    chrome41Txt = self.CHROME_INSECURE_TXT

                # Text output
                certsWithSha1Txt = [
                    '"{0}"'.format(
                        PluginCertInfo._extract_subject_CN_or_OUN(cert))
                    for cert in certsWithSha1
                ]
                outputTxt.append(
                    self.FIELD_FORMAT("Chrome 39 behavior:", chrome39Txt))
                outputTxt.append(
                    self.FIELD_FORMAT("Chrome 40 behavior:", chrome40Txt))
                outputTxt.append(
                    self.FIELD_FORMAT("Chrome 41 behavior:", chrome41Txt))
                outputTxt.append(
                    self.FIELD_FORMAT("Leaf certificate notAfter field:",
                                      leafCertNotAfter))
                outputTxt.append(
                    self.FIELD_FORMAT("SHA1-signed certificates:",
                                      certsWithSha1Txt))

                # XML output
                affectedCertsXml = Element('sha1SignedCertificates')
                for cert in certsWithSha1:
                    affectedCertsXml.append(
                        PluginCertInfo._format_cert_to_xml(
                            cert, '', self._shared_settings['sni']))
                outputXml2.append(affectedCertsXml)

                outputXml2.append(
                    Element('chrome39',
                            behavior=chrome39Txt,
                            isAffected=str(False)
                            if chrome39Txt is 'OK' else str(True)))
                outputXml2.append(
                    Element('chrome40',
                            behavior=chrome40Txt,
                            isAffected=str(False)
                            if chrome40Txt is 'OK' else str(True)))
                outputXml2.append(
                    Element('chrome41',
                            behavior=chrome41Txt,
                            isAffected=str(True)))
                outputXml.append(outputXml2)

        return PluginBase.PluginResult(outputTxt, outputXml)
예제 #37
0
파일: PluginHSTS.py 프로젝트: dud3/sslyze
    def _get_hsts_header(self, target):

        hstsHeader = None
        MAX_REDIRECT = 5
        nb_redirect = 0
        httpGetFormat = 'GET {0} HTTP/1.0\r\nHost: {1}\r\n{2}Connection: close\r\n\r\n'.format
        httpPath = '/'
        httpAppend = ''

        while nb_redirect < MAX_REDIRECT:
            sslConn = create_sslyze_connection(target, self._shared_settings)

            # Perform the SSL handshake
            sslConn.connect()

            sslConn.write(httpGetFormat(httpPath, target[0], httpAppend))
            httpResp = parse_http_response(sslConn.read(2048))
            sslConn.close()

            if httpResp.version == 9:
                # HTTP 0.9 => Probably not an HTTP response
                raise Exception('Server did not return an HTTP response')
            else:
                hstsHeader = httpResp.getheader('strict-transport-security',
                                                False)

            # If there was no HSTS header, check if the server returned a redirection
            if hstsHeader is None and 300 <= httpResp.status < 400:
                redirectHeader = httpResp.getheader('Location', None)
                cookieHeader = httpResp.getheader('Set-Cookie', None)

                if redirectHeader is None:
                    break

                o = urlparse(redirectHeader)
                httpPath = o.path

                # Handle absolute redirection URL
                if o.hostname:
                    if o.port:
                        port = o.port
                    else:
                        if o.scheme == 'https':
                            port = 443
                        elif o.scheme == 'http':
                            # We would have to use urllib for http: URLs
                            raise Exception(
                                "Error: server sent a redirection to HTTP.")
                        else:
                            port = target[2]

                    target = (o.hostname, o.hostname, port, target[3])

                # Handle cookies
                if cookieHeader:
                    cookie = Cookie.SimpleCookie(cookieHeader)

                    if cookie:
                        httpAppend = 'Cookie:' + cookie.output(
                            attrs=[], header='', sep=';') + '\r\n'

                nb_redirect += 1
            else:
                # If the server did not return a redirection just give up
                break

        return hstsHeader