Ejemplo n.º 1
0
def main():
    profile_names = ["old", "intermediate", "modern"]

    parser = argparse.ArgumentParser(
        description=
        "Scans the TLS settings of a server and compares them with a Mozilla TLS profile.",
        epilog="Example usage: python3 run.py www.example.com intermediate",
    )
    parser.add_argument("domain",
                        type=str,
                        help="Domain name of the server to be scanned")
    parser.add_argument(
        "profile",
        type=str,
        nargs="?",
        help=
        "The Mozilla TLS profile to scan for [old|intermediate|modern]. If no profile is specified, the server's TLS settings will be compared to all profiles.",
    )
    parser.add_argument(
        "-c",
        "--ca-file",
        type=str,
        help="Path to a trusted custom root certificates in PEM format",
    )
    parser.add_argument(
        "-w",
        "--cert-expire-warning",
        type=int,
        default=15,
        help=
        "A warning is issued if the certificate expires in less days than specified (default 15 days)",
    )

    args = parser.parse_args()

    domain = args.domain

    profile = args.profile

    if profile and profile not in profile_names:
        raise InvalidProfileName()

    ca_file = args.ca_file
    cert_expire_warning = args.cert_expire_warning

    print("Initialize scanner")
    profiler = TLSProfiler(domain, ca_file, cert_expire_warning)

    print("Run scan (this may take awhile)")
    profiler.scan_server()

    # print result on the console
    if profile:
        print(profiler.compare_to_profile(profile))
    else:
        for p in profile_names:
            print(profiler.compare_to_profile(p))
            print(utils.expand_string("", 90, "-"))
Ejemplo n.º 2
0
    def test_none_server_old_profile(self):
        profiler = TLSProfiler("none.dev.intranet", self.ECDSA_CA_FILE)
        profiler.scan_server()
        result = profiler.compare_to_profile(PROFILE.OLD)

        self.assertCountEqual(self.VALIDATION_ERRORS, result.validation_errors)
        self.assertCountEqual([], result.cert_warnings)
        self.assertFalse(result.validated)
        self.assertCountEqual(
            [
                "Server must choose the cipher suite, not the client (Protocol TLSv1)",
                "Server must choose the cipher suite, not the client (Protocol TLSv1.1)",
                "Server must choose the cipher suite, not the client (Protocol TLSv1.2)",
                "Server must choose the cipher suite, not the client (Protocol TLSv1.3)",
                "Must support ECDHE-ECDSA-AES128-GCM-SHA256",
                "Must not support ECDH curve secp521r1 for key exchange",
                "Must not support ECDH curve X448 for key exchange",
                "Certificate lifespan too long (is 1000, should be less than 366)",
                "Wrong certificate type (is ECDSA), should be one of ['rsa']",
                "OCSP stapling must be supported",
                "Certificate has a wrong signature (is ecdsa-with-SHA384), should be one of ['sha256WithRSAEncryption']",
                "ECDSA certificate uses wrong curve (is secp521r1, should be one of ['prime256v1', 'secp384r1'])",
            ],
            result.profile_errors,
        )
        self.assertFalse(result.profile_matched)
        self.assertEqual(result.vulnerability_errors, [])
        self.assertFalse(result.vulnerable)
        self.assertFalse(result.all_ok)
Ejemplo n.º 3
0
    def test_old_profile(self):
        profiler = TLSProfiler("old.dev.intranet", self.RSA_CA_FILE)
        profiler.scan_server()
        result = profiler.compare_to_profile(PROFILE.OLD)

        self.assertCountEqual(self.VALIDATION_ERRORS, result.validation_errors)
        self.assertCountEqual(
            [
                "Certificate lifespan is 366 days but the recommended lifespan is 90 days."
            ],
            result.cert_warnings,
        )
        self.assertFalse(result.validated)
        self.assertCountEqual(
            [
                "Server has the wrong cipher suites order (Protocol TLSv1.3)",
                "Must support DES-CBC3-SHA",
                "OCSP stapling must be supported",
            ],
            result.profile_errors,
        )
        self.assertFalse(result.profile_matched)
        self.assertEqual(result.vulnerability_errors, [])
        self.assertFalse(result.vulnerable)
        self.assertFalse(result.all_ok)
Ejemplo n.º 4
0
    def test_none_server_modern_profile(self):
        profiler = TLSProfiler("none.dev.intranet", self.ECDSA_CA_FILE)
        profiler.scan_server()
        result = profiler.compare_to_profile(PROFILE.MODERN)

        self.assertCountEqual(self.VALIDATION_ERRORS, result.validation_errors)
        self.assertCountEqual([], result.cert_warnings)
        self.assertFalse(result.validated)
        self.assertCountEqual(
            [
                "Must not support TLSv1.2",
                "Must not support TLSv1.1",
                "Must not support TLSv1",
                "Must not support ECDHE-ECDSA-AES256-SHA",
                "Must not support ECDHE-ECDSA-AES128-SHA256",
                "Must not support ECDHE-ECDSA-AES256-GCM-SHA384",
                "Must not support ECDHE-ECDSA-CHACHA20-POLY1305",
                "Must not support ECDHE-ECDSA-AES128-SHA",
                "Must not support ECDHE-ECDSA-AES256-SHA384",
                "Must not support ECDH curve secp521r1 for key exchange",
                "Must not support ECDH curve X448 for key exchange",
                "Certificate lifespan too long (is 1000, should be less than 90)",
                "ECDSA certificate uses wrong curve (is secp521r1, should be one of ['prime256v1', 'secp384r1'])",
                "OCSP stapling must be supported",
            ],
            result.profile_errors,
        )
        self.assertFalse(result.profile_matched)
        self.assertEqual(result.vulnerability_errors, [])
        self.assertFalse(result.vulnerable)
        self.assertFalse(result.all_ok)
Ejemplo n.º 5
0
    def scan_domain(self, domain):
        scanner = TLSProfiler(domain,
                              ca_file=self.ca_file,
                              cert_expire_warning=self.cert_expire_warning)
        if scanner.server_error is not None:
            self.results["TLS-Other-Error-Domains"].append({
                "domain":
                domain,
                "error":
                scanner.server_error,
            })
            return
        try:
            scanner.scan_server()
            tls_results = scanner.compare_to_profile(self.tls_profile)
        except Exception as e:
            self.results["TLS-Other-Error-Domains"].append({
                "domain": domain,
                "error": str(e),
            })
            return

        if tls_results.all_ok:
            self.results["TLS-Okay-Domains"].append({"domain": domain})

        if not tls_results.validated:
            self.results["TLS-Validation-Fail-Domains"].append({
                "domain":
                domain,
                "errors":
                tls_results.validation_errors
            })

        if not tls_results.no_warnings:
            self.results["TLS-Certificate-Warnings-Domains"].append({
                "domain":
                domain,
                "warnings":
                tls_results.cert_warnings
            })

        if not tls_results.profile_matched:
            self.results["TLS-Profile-Mismatch-Domains"].append({
                "domain":
                domain,
                "errors":
                tls_results.profile_errors,
            })

        if tls_results.vulnerable:
            self.results["TLS-Vulnerability-Domains"].append({
                "domain":
                domain,
                "errors":
                tls_results.vulnerability_errors,
            })
Ejemplo n.º 6
0
    def test_modern_profile(self):
        profiler = TLSProfiler("modern.dev.intranet", self.ECDSA_CA_FILE)
        profiler.scan_server()
        result = profiler.compare_to_profile(PROFILE.MODERN)

        self.assertCountEqual(self.VALIDATION_ERRORS, result.validation_errors)
        self.assertCountEqual([], result.cert_warnings)
        self.assertFalse(result.validated)
        self.assertCountEqual(
            [
                "OCSP stapling must be supported",
            ],
            result.profile_errors,
        )
        self.assertFalse(result.profile_matched)
        self.assertEqual(result.vulnerability_errors, [])
        self.assertFalse(result.vulnerable)
        self.assertFalse(result.all_ok)
Ejemplo n.º 7
0
    def test_intermediate_profile(self):
        profiler = TLSProfiler("intermediate.dev.intranet", self.ECDSA_CA_FILE)
        profiler.scan_server()
        result = profiler.compare_to_profile(PROFILE.INTERMEDIATE)

        self.assertCountEqual(self.VALIDATION_ERRORS, result.validation_errors)
        self.assertCountEqual(["Certificate expires in 12 days"],
                              result.cert_warnings)
        self.assertFalse(result.validated)
        self.assertCountEqual(
            [
                "Client must choose the cipher suite, not the server (Protocol TLSv1.2)",
                "Client must choose the cipher suite, not the server (Protocol TLSv1.3)",
                "OCSP stapling must be supported",
            ],
            result.profile_errors,
        )
        self.assertFalse(result.profile_matched)
        self.assertEqual(result.vulnerability_errors, [])
        self.assertFalse(result.vulnerable)
        self.assertFalse(result.all_ok)