Skip to content

Commit 8b418e4

Browse files
committed
Add new checks to db/categories/template
1 parent e62c42c commit 8b418e4

File tree

9 files changed

+246
-15
lines changed

9 files changed

+246
-15
lines changed

checks/categories.py

Lines changed: 161 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from typing import Optional
44

55
from checks import scoring
6-
from checks.models import TLSClientInitiatedRenegotiationStatus
6+
from checks.models import TLSClientInitiatedRenegotiationStatus, KexRSAPKCSStatus, TLSExtendedMasterSecretStatus
77
from checks.scoring import (
88
ORDERED_STATUSES,
99
STATUS_ERROR,
@@ -185,6 +185,8 @@ def __init__(self, name="web-tls"):
185185
WebTlsZeroRTT,
186186
WebTlsOCSPStapling,
187187
WebTlsKexHashFunc,
188+
WebTlsKexRSAPKCSStatus,
189+
WebTLSExtendedMasterSecret,
188190
# WebTlsDaneRollover,
189191
]
190192
super().__init__(name, subtests)
@@ -257,6 +259,8 @@ def __init__(self, name="mail-tls"):
257259
MailTlsDaneRollover,
258260
MailTlsZeroRTT,
259261
MailTlsKexHashFunc,
262+
MailTlsKexRSAPKCSStatus,
263+
MailTLSExtendedMasterSecret,
260264
# MailTlsOCSPStapling, # Disabled for mail.
261265
]
262266
super().__init__(name, subtests)
@@ -1525,6 +1529,84 @@ def result_phase_out(self):
15251529
self.tech_data = "detail tech data phase-out"
15261530

15271531

1532+
class WebTlsKexRSAPKCSStatus(Subtest):
1533+
def __init__(self):
1534+
super().__init__(
1535+
name="key_exchange_rsa_pkcs",
1536+
label="detail web tls key-exchange-rsa-pkcs label",
1537+
explanation="detail web tls key-exchange-rsa-pkcs exp",
1538+
tech_string="detail web tls key-exchange-rsa-pkcs tech table",
1539+
worst_status=scoring.TLS_KEX_RSA_PKCS_WORST_STATUS,
1540+
full_score=scoring.TLS_KEX_RSA_PKCS_GOOD,
1541+
model_score_field="key_exchange_rsa_pkcs_score",
1542+
)
1543+
1544+
def save_result(self, status: KexRSAPKCSStatus):
1545+
handlers = {
1546+
KexRSAPKCSStatus.good: self.result_good,
1547+
KexRSAPKCSStatus.bad: self.result_bad,
1548+
KexRSAPKCSStatus.unknown: self.result_unknown,
1549+
}
1550+
return handlers[status]()
1551+
1552+
def result_good(self):
1553+
self._status(STATUS_SUCCESS)
1554+
self.verdict = "detail web tls key-exchange-rsa-pkcs verdict good"
1555+
self.tech_data = "detail tech data good"
1556+
1557+
def result_bad(self):
1558+
self._status(STATUS_FAIL)
1559+
self.verdict = "detail web tls key-exchange-rsa-pkcs verdict bad"
1560+
self.tech_data = "detail tech data insufficient"
1561+
1562+
def result_unknown(self):
1563+
self._status(STATUS_INFO)
1564+
self.verdict = "detail web tls key-exchange-rsa-pkcs verdict other"
1565+
self.tech_data = "detail tech data not-applicable"
1566+
1567+
1568+
class WebTLSExtendedMasterSecret(Subtest):
1569+
def __init__(self):
1570+
super().__init__(
1571+
name="extended_master_secret",
1572+
label="detail web tls extended-master-secret label",
1573+
explanation="detail web tls extended-master-secret exp",
1574+
tech_string="detail web tls extended-master-secret tech table",
1575+
worst_status=scoring.TLS_EXTENDED_MASTER_SECRET_WORST_STATUS,
1576+
full_score=scoring.TLS_EXTENDED_MASTER_SECRET_GOOD,
1577+
model_score_field="extended_master_secret_score",
1578+
)
1579+
1580+
def save_result(self, status: TLSExtendedMasterSecretStatus):
1581+
handlers = {
1582+
TLSExtendedMasterSecretStatus.supported: self.result_good,
1583+
TLSExtendedMasterSecretStatus.na_no_tls_1_2: self.result_na_no_tls_1_2,
1584+
TLSExtendedMasterSecretStatus.not_supported: self.result_bad,
1585+
TLSExtendedMasterSecretStatus.unknown: self.result_unknown,
1586+
}
1587+
return handlers[status]()
1588+
1589+
def result_good(self):
1590+
self._status(STATUS_SUCCESS)
1591+
self.verdict = "detail web tls extended-master-secret verdict good"
1592+
self.tech_data = "detail tech data good"
1593+
1594+
def result_bad(self):
1595+
self._status(STATUS_FAIL)
1596+
self.verdict = "detail web tls extended-master-secret verdict bad"
1597+
self.tech_data = "detail tech data insufficient"
1598+
1599+
def result_unknown(self):
1600+
self._status(STATUS_INFO)
1601+
self.verdict = "detail web tls extended-master-secret verdict other"
1602+
self.tech_data = "detail tech data not-applicable"
1603+
1604+
def result_na_no_tls_1_2(self):
1605+
self._status(STATUS_NOTICE)
1606+
self.verdict = "detail web tls extended-master-secret verdict na-no-tls-1-2"
1607+
self.tech_data = "detail tech data phase-out"
1608+
1609+
15281610
class MailTlsStarttlsExists(Subtest):
15291611
def __init__(self):
15301612
super().__init__(
@@ -2115,6 +2197,84 @@ def result_phase_out(self):
21152197
self.tech_data = "detail tech data phase-out"
21162198

21172199

2200+
class MailTlsKexRSAPKCSStatus(Subtest):
2201+
def __init__(self):
2202+
super().__init__(
2203+
name="key_exchange_rsa_pkcs",
2204+
label="detail mail tls key-exchange-rsa-pkcs label",
2205+
explanation="detail mail tls key-exchange-rsa-pkcs exp",
2206+
tech_string="detail mail tls key-exchange-rsa-pkcs tech table",
2207+
worst_status=scoring.TLS_KEX_RSA_PKCS_WORST_STATUS,
2208+
full_score=scoring.TLS_KEX_RSA_PKCS_GOOD,
2209+
model_score_field="key_exchange_rsa_pkcs_score",
2210+
)
2211+
2212+
def save_result(self, status: KexRSAPKCSStatus):
2213+
handlers = {
2214+
KexRSAPKCSStatus.good: self.result_good,
2215+
KexRSAPKCSStatus.bad: self.result_bad,
2216+
KexRSAPKCSStatus.unknown: self.result_unknown,
2217+
}
2218+
return handlers[status]()
2219+
2220+
def result_good(self):
2221+
self._status(STATUS_SUCCESS)
2222+
self.verdict = "detail mail tls key-exchange-rsa-pkcs verdict good"
2223+
self.tech_data = "detail tech data good"
2224+
2225+
def result_bad(self):
2226+
self._status(STATUS_FAIL)
2227+
self.verdict = "detail mail tls key-exchange-rsa-pkcs verdict bad"
2228+
self.tech_data = "detail tech data insufficient"
2229+
2230+
def result_unknown(self):
2231+
self._status(STATUS_INFO)
2232+
self.verdict = "detail mail tls key-exchange-rsa-pkcs verdict other"
2233+
self.tech_data = "detail tech data not-applicable"
2234+
2235+
2236+
class MailTLSExtendedMasterSecret(Subtest):
2237+
def __init__(self):
2238+
super().__init__(
2239+
name="extended_master_secret",
2240+
label="detail mail tls extended-master-secret label",
2241+
explanation="detail mail tls extended-master-secret exp",
2242+
tech_string="detail mail tls extended-master-secret tech table",
2243+
worst_status=scoring.TLS_EXTENDED_MASTER_SECRET_WORST_STATUS,
2244+
full_score=scoring.TLS_EXTENDED_MASTER_SECRET_GOOD,
2245+
model_score_field="extended_master_secret_score",
2246+
)
2247+
2248+
def save_result(self, status: TLSExtendedMasterSecretStatus):
2249+
handlers = {
2250+
TLSExtendedMasterSecretStatus.supported: self.result_good,
2251+
TLSExtendedMasterSecretStatus.na_no_tls_1_2: self.result_na_no_tls_1_2,
2252+
TLSExtendedMasterSecretStatus.not_supported: self.result_bad,
2253+
TLSExtendedMasterSecretStatus.unknown: self.result_unknown,
2254+
}
2255+
return handlers[status]()
2256+
2257+
def result_good(self):
2258+
self._status(STATUS_SUCCESS)
2259+
self.verdict = "detail mail tls extended-master-secret verdict good"
2260+
self.tech_data = "detail tech data good"
2261+
2262+
def result_bad(self):
2263+
self._status(STATUS_FAIL)
2264+
self.verdict = "detail mail tls extended-master-secret verdict bad"
2265+
self.tech_data = "detail tech data insufficient"
2266+
2267+
def result_unknown(self):
2268+
self._status(STATUS_INFO)
2269+
self.verdict = "detail mail tls extended-master-secret verdict other"
2270+
self.tech_data = "detail tech data not-applicable"
2271+
2272+
def result_na_no_tls_1_2(self):
2273+
self._status(STATUS_NOTICE)
2274+
self.verdict = "detail mail tls extended-master-secret verdict na-no-tls-1-2"
2275+
self.tech_data = "detail tech data phase-out"
2276+
2277+
21182278
class MailTlsDaneExists(Subtest):
21192279
def __init__(self):
21202280
super().__init__(
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# Generated by Django 4.2.22 on 2025-08-12 12:28
2+
3+
import checks.models
4+
from django.db import migrations, models
5+
import enumfields.fields
6+
7+
8+
class Migration(migrations.Migration):
9+
dependencies = [
10+
("checks", "0019_domaintesttls_client_reneg_to_enum"),
11+
]
12+
13+
operations = [
14+
migrations.AddField(
15+
model_name="domaintesttls",
16+
name="extended_master_secret",
17+
field=enumfields.fields.EnumField(
18+
default=3,
19+
enum=checks.models.TLSExtendedMasterSecretStatus,
20+
max_length=10,
21+
),
22+
),
23+
migrations.AddField(
24+
model_name="domaintesttls",
25+
name="extended_master_secret_score",
26+
field=models.IntegerField(null=True),
27+
),
28+
migrations.AddField(
29+
model_name="domaintesttls",
30+
name="key_exchange_rsa_pkcs",
31+
field=enumfields.fields.EnumField(default=2, enum=checks.models.KexRSAPKCSStatus, max_length=10),
32+
),
33+
migrations.AddField(
34+
model_name="domaintesttls",
35+
name="key_exchange_rsa_pkcs_score",
36+
field=models.IntegerField(null=True),
37+
),
38+
]

checks/models.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -550,6 +550,12 @@ class DomainTestTls(BaseTestModel):
550550
kex_hash_func = EnumField(KexHashFuncStatus, default=KexHashFuncStatus.bad)
551551
kex_hash_func_score = models.IntegerField(null=True)
552552

553+
key_exchange_rsa_pkcs = EnumField(KexRSAPKCSStatus, default=KexRSAPKCSStatus.unknown)
554+
key_exchange_rsa_pkcs_score = models.IntegerField(null=True)
555+
556+
extended_master_secret = EnumField(TLSExtendedMasterSecretStatus, default=TLSExtendedMasterSecretStatus.unknown)
557+
extended_master_secret_score = models.IntegerField(null=True)
558+
553559
forced_https = EnumField(ForcedHttpsStatus, default=ForcedHttpsStatus.bad)
554560
forced_https_score = models.IntegerField(null=True)
555561

@@ -628,6 +634,10 @@ def __dir__(self):
628634
"ocsp_stapling_score",
629635
"kex_hash_func",
630636
"kex_hash_func_score",
637+
"key_exchange_rsa_pkcs",
638+
"key_exchange_rsa_pkcs_score",
639+
"extended_master_secret",
640+
"extended_master_secret_score",
631641
"forced_https",
632642
"forced_https_score",
633643
"http_compression_enabled",
@@ -673,6 +683,8 @@ def get_web_api_details(self):
673683
"zero_rtt": self.zero_rtt.name,
674684
"ocsp_stapling": self.ocsp_stapling.name,
675685
"kex_hash_func": self.kex_hash_func.name,
686+
"key_exchange_rsa_pkcs": self.key_exchange_rsa_pkcs.name,
687+
"extended_master_secret": self.extended_master_secret.name,
676688
"https_redirect": self.forced_https.name,
677689
"http_compression": self.http_compression_enabled,
678690
"hsts": self.hsts_enabled,
@@ -708,6 +720,8 @@ def get_mail_api_details(self):
708720
"client_reneg": self.client_reneg,
709721
"zero_rtt": self.zero_rtt.name,
710722
"kex_hash_func": self.kex_hash_func.name,
723+
"key_exchange_rsa_pkcs": self.key_exchange_rsa_pkcs.name,
724+
"extended_master_secret": self.extended_master_secret.name,
711725
"cert_chain": self.cert_chain,
712726
"cert_trusted": self.cert_trusted,
713727
"cert_pubkey_bad": self.cert_pubkey_bad,

checks/scoring.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -165,10 +165,10 @@
165165
WEB_TLS_HOSTMATCH_BAD = NO_POINTS
166166
WEB_TLS_HOSTMATCH_WORST_STATUS = STATUS_FAIL
167167

168-
WEB_TLS_EXTENDED_MASTER_SECRET_GOOD = FULL_WEIGHT_POINTS
169-
WEB_TLS_EXTENDED_MASTER_SECRET_OK = FULL_WEIGHT_POINTS
170-
WEB_TLS_EXTENDED_MASTER_SECRET_BAD = NO_POINTS
171-
WEB_TLS_EXTENDED_MASTER_SECRET_WORST_STATUS = STATUS_FAIL
168+
TLS_EXTENDED_MASTER_SECRET_GOOD = FULL_WEIGHT_POINTS
169+
TLS_EXTENDED_MASTER_SECRET_OK = FULL_WEIGHT_POINTS
170+
TLS_EXTENDED_MASTER_SECRET_BAD = NO_POINTS
171+
TLS_EXTENDED_MASTER_SECRET_WORST_STATUS = STATUS_FAIL
172172

173173
CAA_GOOD = FULL_WEIGHT_POINTS
174174
CAA_BAD = NO_POINTS
@@ -196,10 +196,10 @@
196196
WEB_TLS_OCSP_STAPLING_BAD = NO_POINTS
197197
WEB_TLS_OCSP_STAPLING_WORST_STATUS = STATUS_NOTICE
198198

199-
WEB_TLS_KEX_RSA_PKCS_GOOD = FULL_WEIGHT_POINTS
200-
WEB_TLS_KEX_RSA_PKCS_OK = FULL_WEIGHT_POINTS
201-
WEB_TLS_KEX_RSA_PKCS_BAD = NO_POINTS
202-
WEB_TLS_KEX_RSA_PKCS_WORST_STATUS = STATUS_NOTICE
199+
TLS_KEX_RSA_PKCS_GOOD = FULL_WEIGHT_POINTS
200+
TLS_KEX_RSA_PKCS_OK = FULL_WEIGHT_POINTS
201+
TLS_KEX_RSA_PKCS_BAD = NO_POINTS
202+
TLS_KEX_RSA_PKCS_WORST_STATUS = STATUS_NOTICE
203203

204204
WEB_TLS_KEX_HASH_FUNC_GOOD = FULL_WEIGHT_POINTS
205205
WEB_TLS_KEX_HASH_FUNC_OK = FULL_WEIGHT_POINTS

checks/tasks/tls/evaluation.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
TLSClientInitiatedRenegotiationStatus,
2525
TLSExtendedMasterSecretStatus,
2626
)
27-
from checks.scoring import WEB_TLS_EXTENDED_MASTER_SECRET_GOOD, WEB_TLS_EXTENDED_MASTER_SECRET_BAD
27+
from checks.scoring import TLS_EXTENDED_MASTER_SECRET_GOOD, TLS_EXTENDED_MASTER_SECRET_BAD
2828
from checks.tasks.tls.tls_constants import (
2929
PROTOCOLS_GOOD,
3030
PROTOCOLS_SUFFICIENT,
@@ -353,7 +353,7 @@ class TLSExtendedMasterSecretEvaluation:
353353
"""
354354

355355
status: TLSExtendedMasterSecretStatus = TLSExtendedMasterSecretStatus.na_no_tls_1_2
356-
score: scoring.Score = WEB_TLS_EXTENDED_MASTER_SECRET_GOOD
356+
score: scoring.Score = TLS_EXTENDED_MASTER_SECRET_GOOD
357357

358358
def update_for_connection(self, ssl_connection: SslConnection, tls_version: TlsVersionEnum) -> None:
359359
if tls_version != TlsVersionEnum.TLS_1_2:
@@ -362,10 +362,10 @@ def update_for_connection(self, ssl_connection: SslConnection, tls_version: TlsV
362362
ems_support = ssl_connection.ssl_client.get_extended_master_secret_support()
363363
if ems_support == ExtendedMasterSecretSupportEnum.USED_IN_CURRENT_SESSION:
364364
self.status = TLSExtendedMasterSecretStatus.supported
365-
self.score = WEB_TLS_EXTENDED_MASTER_SECRET_GOOD
365+
self.score = TLS_EXTENDED_MASTER_SECRET_GOOD
366366
elif ems_support == ExtendedMasterSecretSupportEnum.NOT_USED_IN_CURRENT_SESSION:
367367
self.status = TLSExtendedMasterSecretStatus.not_supported
368-
self.score = WEB_TLS_EXTENDED_MASTER_SECRET_BAD
368+
self.score = TLS_EXTENDED_MASTER_SECRET_BAD
369369

370370

371371
def _unique_unhashable(items: List[Any]) -> List[Any]:

checks/tasks/tls/scans.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -886,12 +886,12 @@ def test_key_exchange_rsa_pkcs(
886886
log.info(f"RSA-PKCS key exchange check: negotiated bad sigalg ({rsa_pkcs_result})")
887887
return KeyExchangeRSAPKCSFunctionEvaluation(
888888
status=KexRSAPKCSStatus.bad,
889-
score=scoring.WEB_TLS_KEX_RSA_PKCS_BAD,
889+
score=scoring.TLS_KEX_RSA_PKCS_BAD,
890890
)
891891

892892
return KeyExchangeRSAPKCSFunctionEvaluation(
893893
status=KexRSAPKCSStatus.good,
894-
score=scoring.WEB_TLS_KEX_RSA_PKCS_GOOD,
894+
score=scoring.TLS_KEX_RSA_PKCS_GOOD,
895895
)
896896

897897

checks/tasks/tls/tasks_reports.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,10 @@ def save_results(model, results, addr, domain, category):
275275
model.ocsp_stapling_score = result.get("ocsp_stapling_score")
276276
model.kex_hash_func = result.get("kex_hash_func")
277277
model.kex_hash_func_score = result.get("kex_hash_func_score")
278+
model.key_exchange_rsa_pkcs = result.get("key_exchange_rsa_pkcs")
279+
model.key_exchange_rsa_pkcs_score = result.get("key_exchange_rsa_pkcs_score")
280+
model.extended_master_secret = result.get("extended_master_secret")
281+
model.extended_master_secret_score = result.get("extended_master_secret_score")
278282

279283
elif testname == "cert" and result.get("tls_cert"):
280284
model.cert_chain = result.get("chain")
@@ -350,6 +354,10 @@ def save_results(model, results, addr, domain, category):
350354
# model.ocsp_stapling_score = result.get("ocsp_stapling_score")
351355
model.kex_hash_func = result.get("kex_hash_func")
352356
model.kex_hash_func_score = result.get("kex_hash_func_score")
357+
model.key_exchange_rsa_pkcs = result.get("key_exchange_rsa_pkcs")
358+
model.key_exchange_rsa_pkcs_score = result.get("key_exchange_rsa_pkcs_score")
359+
model.extended_master_secret = result.get("extended_master_secret")
360+
model.extended_master_secret_score = result.get("extended_master_secret_score")
353361
if result.get("tls_cert"):
354362
model.cert_chain = result.get("chain")
355363
model.cert_trusted = result.get("trusted")
@@ -574,6 +582,9 @@ def annotate_and_combine_all(good_items, sufficient_items, bad_items, phaseout_i
574582
elif dttls.kex_hash_func == KexHashFuncStatus.phase_out:
575583
category.subtests["kex_hash_func"].result_phase_out()
576584

585+
category.subtests["key_exchange_rsa_pkcs"].save_result(dttls.key_exchange_rsa_pkcs)
586+
category.subtests["extended_master_secret"].save_result(dttls.extended_master_secret)
587+
577588
elif isinstance(category, categories.MailTls):
578589
if dttls.could_not_test_smtp_starttls:
579590
category.subtests["starttls_exists"].result_could_not_test()
@@ -736,6 +747,9 @@ def annotate_and_combine_all(good_items, sufficient_items, bad_items, phaseout_i
736747
elif dttls.kex_hash_func == KexHashFuncStatus.phase_out:
737748
category.subtests["kex_hash_func"].result_phase_out()
738749

750+
category.subtests["key_exchange_rsa_pkcs"].save_result(dttls.key_exchange_rsa_pkcs)
751+
category.subtests["extended_master_secret"].save_result(dttls.extended_master_secret)
752+
739753
dttls.report = category.gen_report()
740754

741755

0 commit comments

Comments
 (0)