Example #1
0
 def test_none_server_old_profile(self):
     profiler = TLSProfiler("none.dev.intranet", PROFILE.OLD,
                            self.ECDSA_CA_FILE)
     result = profiler.run()
     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)
Example #2
0
 def test_none_server_modern_profile(self):
     profiler = TLSProfiler("none.dev.intranet", PROFILE.MODERN,
                            self.ECDSA_CA_FILE)
     result = profiler.run()
     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)
Example #3
0
 def test_none_server_intermediate_profile(self):
     profiler = TLSProfiler("none.dev.intranet", PROFILE.INTERMEDIATE,
                            self.ECDSA_CA_FILE)
     result = profiler.run()
     self.assertCountEqual(self.VALIDATION_ERRORS, result.validation_errors)
     self.assertCountEqual([], result.cert_warnings)
     self.assertFalse(result.validated)
     self.assertCountEqual(
         [
             "must not support TLSv1.1",
             "must not support TLSv1",
             "client must choose the cipher suite, not the server (Protocol TLSv1.3)",
             "must not support ECDHE-ECDSA-AES256-SHA",
             "must not support ECDHE-ECDSA-AES128-SHA256",
             "must not support ECDHE-ECDSA-AES128-SHA",
             "must not support ECDHE-ECDSA-AES256-SHA384",
             "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 730)",
             "OCSP stapling must be supported",
             "ECDSA certificate uses wrong curve (is secp521r1, should be one of ['prime256v1', 'secp384r1', 'secp256r1', 'secp256r1', 'prime256v1'])",
         ],
         result.profile_errors,
     )
     self.assertFalse(result.profile_matched)
     self.assertEqual(result.vulnerability_errors, [])
     self.assertFalse(result.vulnerable)
     self.assertFalse(result.all_ok)
Example #4
0
    def scan_domain(self, domain):
        scanner = TLSProfiler(domain, self.tls_profile, ca_file=self.ca_file)
        if scanner.server_error is not None:
            self.results["TLS-Other-Error-Domains"].append({
                "domain":
                domain,
                "error":
                scanner.server_error,
            })
            return
        try:
            tls_results = scanner.run()
        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,
            })
Example #5
0
def run_scan(domain: str, profile: str) -> TLSProfilerResult:
    result = None
    try:
        profiler = TLSProfiler(domain, profile)
        result = profiler.run()
    except Exception as e:
        return {"error": e}

    if result is None:
        return {"error": profiler.server_error}

    return dataclasses.asdict(result)
Example #6
0
def main():
    valid_profiles = ["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,
        help="The Mozilla TLS profile to scan for [old|intermediate|modern]",
    )
    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 not in valid_profiles:
        raise InvalidProfileName()

    ca_file = args.ca_file
    cert_expire_warning = args.cert_expire_warning

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

    print("Run scan (this may take awhile)")
    result = profiler.run()
    print(result)
Example #7
0
 def test_modern_profile(self):
     profiler = TLSProfiler("modern.dev.intranet", PROFILE.MODERN,
                            self.ECDSA_CA_FILE)
     result = profiler.run()
     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)
Example #8
0
 def test_old_profile(self):
     profiler = TLSProfiler("old.dev.intranet", PROFILE.OLD,
                            self.RSA_CA_FILE)
     result = profiler.run()
     self.assertCountEqual(self.VALIDATION_ERRORS, result.validation_errors)
     self.assertCountEqual([], 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)
Example #9
0
 def test_intermediate_profile(self):
     profiler = TLSProfiler("intermediate.dev.intranet",
                            PROFILE.INTERMEDIATE, self.ECDSA_CA_FILE)
     result = profiler.run()
     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.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)
Example #10
0
)
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 not in valid_profiles:
    raise InvalidProfileName()

ca_file = args.ca_file
cert_expire_warning = args.cert_expire_warning

profiler = TLSProfiler(domain, profile, ca_file, cert_expire_warning)

print(profiler.run())