Skip to content

Commit 5bf43eb

Browse files
committed
Add new checks to db/categories/template
1 parent cca9027 commit 5bf43eb

File tree

9 files changed

+242
-15
lines changed

9 files changed

+242
-15
lines changed

checks/categories.py

Lines changed: 157 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,
@@ -1525,6 +1525,84 @@ def result_phase_out(self):
15251525
self.tech_data = "detail tech data phase-out"
15261526

15271527

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

21172195

2196+
class MailKexRSAPKCSStatus(Subtest):
2197+
def __init__(self):
2198+
super().__init__(
2199+
name="key_exchange_rsa_pkcs",
2200+
label="detail mail tls key-exchange-rsa-pkcs label",
2201+
explanation="detail mail tls key-exchange-rsa-pkcs exp",
2202+
tech_string="detail mail tls key-exchange-rsa-pkcs tech table",
2203+
worst_status=scoring.TLS_KEX_RSA_PKCS_WORST_STATUS,
2204+
full_score=scoring.TLS_KEX_RSA_PKCS_GOOD,
2205+
model_score_field="key_exchange_rsa_pkcs_score",
2206+
)
2207+
2208+
def save_result(self, status: KexRSAPKCSStatus):
2209+
handlers = {
2210+
KexRSAPKCSStatus.good: self.result_good,
2211+
KexRSAPKCSStatus.bad: self.result_bad,
2212+
KexRSAPKCSStatus.unknown: self.result_unknown,
2213+
}
2214+
return handlers[status]()
2215+
2216+
def result_good(self):
2217+
self._status(STATUS_SUCCESS)
2218+
self.verdict = "detail mail tls key-exchange-rsa-pkcs verdict good"
2219+
self.tech_data = "detail tech data good"
2220+
2221+
def result_bad(self):
2222+
self._status(STATUS_FAIL)
2223+
self.verdict = "detail mail tls key-exchange-rsa-pkcs verdict bad"
2224+
self.tech_data = "detail tech data insufficient"
2225+
2226+
def result_unknown(self):
2227+
self._status(STATUS_INFO)
2228+
self.verdict = "detail mail tls key-exchange-rsa-pkcs verdict other"
2229+
self.tech_data = "detail tech data not-applicable"
2230+
2231+
2232+
class MailTLSExtendedMasterSecret(Subtest):
2233+
def __init__(self):
2234+
super().__init__(
2235+
name="extended_master_secret",
2236+
label="detail mail tls extended-master-secret label",
2237+
explanation="detail mail tls extended-master-secret exp",
2238+
tech_string="detail mail tls extended-master-secret tech table",
2239+
worst_status=scoring.TLS_EXTENDED_MASTER_SECRET_WORST_STATUS,
2240+
full_score=scoring.TLS_EXTENDED_MASTER_SECRET_GOOD,
2241+
model_score_field="extended_master_secret_score",
2242+
)
2243+
2244+
def save_result(self, status: TLSExtendedMasterSecretStatus):
2245+
handlers = {
2246+
TLSExtendedMasterSecretStatus.supported: self.result_good,
2247+
TLSExtendedMasterSecretStatus.na_no_tls_1_2: self.result_na_no_tls_1_2,
2248+
TLSExtendedMasterSecretStatus.not_supported: self.result_bad,
2249+
TLSExtendedMasterSecretStatus.unknown: self.result_unknown,
2250+
}
2251+
return handlers[status]()
2252+
2253+
def result_good(self):
2254+
self._status(STATUS_SUCCESS)
2255+
self.verdict = "detail mail tls extended-master-secret verdict good"
2256+
self.tech_data = "detail tech data good"
2257+
2258+
def result_bad(self):
2259+
self._status(STATUS_FAIL)
2260+
self.verdict = "detail mail tls extended-master-secret verdict bad"
2261+
self.tech_data = "detail tech data insufficient"
2262+
2263+
def result_unknown(self):
2264+
self._status(STATUS_INFO)
2265+
self.verdict = "detail mail tls extended-master-secret verdict other"
2266+
self.tech_data = "detail tech data not-applicable"
2267+
2268+
def result_na_no_tls_1_2(self):
2269+
self._status(STATUS_NOTICE)
2270+
self.verdict = "detail mail tls extended-master-secret verdict na-no-tls-1-2"
2271+
self.tech_data = "detail tech data phase-out"
2272+
2273+
21182274
class MailTlsDaneExists(Subtest):
21192275
def __init__(self):
21202276
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

interface/templates/domain-results.html

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,14 @@ <h1>
4242
{% include "details-test-item.html" with testitem=details.tls_cipher_order %}
4343
{% include "details-test-item.html" with testitem=details.fs_params %}
4444
{% include "details-test-item.html" with testitem=details.kex_hash_func %}
45+
{% include "details-test-item.html" with testitem=details.kex_hash_func %}
46+
{% include "details-test-item.html" with testitem=details.key_exchange_rsa_pkcs %}
4547
{% include "details-test-item.html" with testitem=details.tls_compression %}
4648
{% include "details-test-item.html" with testitem=details.renegotiation_secure %}
4749
{% include "details-test-item.html" with testitem=details.renegotiation_client %}
4850
{% include "details-test-item.html" with testitem=details.zero_rtt %}
4951
{% include "details-test-item.html" with testitem=details.ocsp_stapling %}
52+
{% include "details-test-item.html" with testitem=details.extended_master_secret %}
5053
<div class="test-subsection">
5154
{% include "string.html" with name="results domain-mail tls certificate label" %}
5255
</div>

0 commit comments

Comments
 (0)