Skip to content

Commit 69fdfbf

Browse files
authored
Windows/Crypto rework: CertTree, CSR, PKINIT, Netlogon's Kerberos secure channel, older NTLM and more (#4879)
* Implement CMS signing/verification * Implement PKINIT in AS-REQ + Improve SPNEGOSSP getter * NTLM: add old variant support * DCE/RPC: improve context handling * Kerberos: fix passive with DCE/RPC + improve deleg * MS-NRPC: support Kerberos secure channel * Fix case in Kerberos check * HTTP client: allow to drop channel bindings * Add Kerberos doc * PEP8 fixes * Cert.py: fix TreeChain tests * Add missing NETLOGON flags * SPNEGO: support reading KRB5CCNAME * SPNEGO: add tests & fix bugs * Update IKEv2 tests with new X509_AlgorithmIdentifier * doc: add FAST documentation * More correct omit * PEP8 & CI * Fix send test * Handle missing cryptography * SPNEGO: big refactor * Increase debugging logs * Add CSR parsing * cryptography test: include more crypto tests * Remove spnego.uts from test configurations Removed spnego.uts from the cryptography test configurations.
1 parent e73137e commit 69fdfbf

35 files changed

+5236
-1368
lines changed

.github/workflows/cifuzz.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name: CIFuzz
22

33
on:
4-
pull_request:
4+
push:
55
branches: [master]
66

77
permissions:

doc/scapy/layers/kerberos.rst

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,11 @@ This section tries to give many usage examples, but isn't exhaustive. For more d
4141
>>> t.show()
4242
Tickets:
4343
44-
Start time End time Renew until Auth time
44+
Start time End time Renew until Auth time
4545
31/08/23 11:38:34 31/08/23 21:38:34 31/08/23 21:38:35 31/08/23 01:38:34
4646
4747
48-
Start time End time Renew until Auth time
48+
Start time End time Renew until Auth time
4949
31/08/23 11:39:07 31/08/23 21:38:34 31/08/23 21:38:35 31/08/23 01:38:34
5050
5151
@@ -68,12 +68,41 @@ This section tries to give many usage examples, but isn't exhaustive. For more d
6868
>>> # Using the AES-256-SHA1-96 Kerberos Key
6969
>>> t.request_tgt("[email protected]", key=Key(EncryptionType.AES256_CTS_HMAC_SHA1_96, bytes.fromhex("63a2577d8bf6abeba0847cded36b9aed202c23750eb9c56b6155be1cc946bb1d")))
7070
71+
- **Request a TGT using PKINIT**:
72+
73+
.. code:: pycon
74+
75+
>>> from scapy.libs.rfc3961 import EncryptionType
76+
>>> load_module("ticketer")
77+
>>> t = Ticketer()
78+
>>> # If P12:
79+
>>> t.request_tgt("[email protected]", p12="admin.pfx", ca="ca.pem")
80+
>>> # One could also have used a different cert and key file:
81+
>>> t.request_tgt("[email protected]", x509="admin.cert", x509key="admin.key", ca="ca.pem")
82+
83+
- **Request a user TGT with Kerberos armoring (FAST)**
84+
85+
The ``armor_with`` keyword allows to select a ticket to armor the request with.
86+
87+
.. code:: pycon
88+
89+
>>> load_module("ticketer")
90+
>>> t = Ticketer()
91+
>>> t.request_tgt("[email protected]", key=Key(EncryptionType.RC4_HMAC, bytes.fromhex("2b576acbe6bcfda7294d6bd18041b8fe")))
92+
>>> t.show()
93+
Tickets:
94+
95+
Start time End time Renew until Auth time
96+
31/08/23 11:38:34 31/08/23 21:38:34 31/08/23 21:38:35 31/08/23 01:38:34
97+
>>> t.request_tgt("[email protected]", armor_with=0) # Armor with ticket n°0
98+
7199
- **Renew a TGT or ST**:
72100

73101
.. code::
74102
75103
>>> t.renew(0) # renew TGT
76104
>>> t.renew(1) # renew ST. Works only with 'host/' SPNs
105+
>>> t.renew(1, armor_with=0) # renew something with armoring
77106
78107
- **Import tickets from a ccache**:
79108

scapy/asn1/mib.py

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -284,16 +284,25 @@ def load_mib(filenames):
284284
"1.3.101.113": "Ed448",
285285
}
286286

287+
# pkcs3 #
288+
289+
pkcs3_oids = {
290+
"1.2.840.113549.1.3": "pkcs-3",
291+
"1.2.840.113549.1.3.1": "dhKeyAgreement",
292+
}
293+
287294
# pkcs7 #
288295

289296
pkcs7_oids = {
297+
"1.2.840.113549.1.7": "pkcs-7",
290298
"1.2.840.113549.1.7.2": "id-signedData",
299+
"1.2.840.113549.1.7.3": "id-envelopedData",
291300
}
292301

293302
# pkcs9 #
294303

295304
pkcs9_oids = {
296-
"1.2.840.113549.1.9": "pkcs9",
305+
"1.2.840.113549.1.9": "pkcs-9",
297306
"1.2.840.113549.1.9.0": "modules",
298307
"1.2.840.113549.1.9.1": "emailAddress",
299308
"1.2.840.113549.1.9.2": "unstructuredName",
@@ -320,6 +329,13 @@ def load_mib(filenames):
320329
"1.2.840.113549.1.9.52": "id-aa-CMSAlgorithmProtection"
321330
}
322331

332+
# enc algs #
333+
334+
encAlgs_oids = {
335+
"1.2.840.113549.3.4": "rc4",
336+
"1.2.840.113549.3.7": "des-ede3-cbc",
337+
}
338+
323339
# x509 #
324340

325341
attributeType_oids = {
@@ -492,10 +508,21 @@ def load_mib(filenames):
492508
"2.5.29.67": "id-ce-allowedAttAss",
493509
"2.5.29.68": "id-ce-attributeMappings",
494510
"2.5.29.69": "id-ce-holderNameConstraints",
495-
# [MS-WCCE]
496-
"1.3.6.1.4.1.311.2.1.14": "CERT_EXTENSIONS",
497-
"1.3.6.1.4.1.311.10.3.4": "szOID_EFS_CRYPTO",
511+
# [MS-WCCE] + wincrypt.h
512+
"1.3.6.1.4.1.311.2.1.14": "OID_CERT_EXTENSIONS",
513+
"1.3.6.1.4.1.311.10.3.4": "OID_EFS_CRYPTO",
514+
"1.3.6.1.4.1.311.13.2.1": "OID_ENROLLMENT_NAME_VALUE_PAIR",
515+
"1.3.6.1.4.1.311.13.2.2": "OID_ENROLLMENT_CSP_PROVIDER",
516+
"1.3.6.1.4.1.311.13.2.3": "OID_OS_VERSION",
517+
"1.3.6.1.4.1.311.10.10.1": "OID_CMC_ADD_ATTRIBUTES",
498518
"1.3.6.1.4.1.311.20.2": "ENROLL_CERTTYPE",
519+
"1.3.6.1.4.1.311.21.10": "OID_APPLICATION_CERT_POLICIES",
520+
"1.3.6.1.4.1.311.21.20": "OID_REQUEST_CLIENT_INFO",
521+
"1.3.6.1.4.1.311.21.23": "OID_ENROLL_EK_INFO",
522+
"1.3.6.1.4.1.311.21.24": "OID_ENROLL_ATTESTATION_STATEMENT",
523+
"1.3.6.1.4.1.311.21.25": "OID_ENROLL_KSP_NAME",
524+
"1.3.6.1.4.1.311.21.39": "OID_ENROLL_AIK_INFO",
525+
"1.3.6.1.4.1.311.21.7": "OID_CERTIFICATE_TEMPLATE",
499526
"1.3.6.1.4.1.311.25.1": "NTDS_REPLICATION",
500527
"1.3.6.1.4.1.311.25.2": "NTDS_CA_SECURITY_EXT",
501528
"1.3.6.1.4.1.311.25.2.1": "NTDS_OBJECTSID",
@@ -551,6 +578,15 @@ def load_mib(filenames):
551578
"1.3.6.1.5.5.7.3.22": "secureShellServer"
552579
}
553580

581+
certPkixCmc_oids = {
582+
"1.3.6.1.5.5.7.7.8": "id-cmc-addExtensions",
583+
}
584+
585+
certPkixCct_oids = {
586+
"1.3.6.1.5.5.7.12.2": "id-cct-PKIData",
587+
"1.3.6.1.5.5.7.12.3": "id-cct-PKIResponse",
588+
}
589+
554590
certPkixAd_oids = {
555591
"1.3.6.1.5.5.7.48.1": "ocsp",
556592
"1.3.6.1.5.5.7.48.2": "caIssuers",
@@ -563,6 +599,11 @@ def load_mib(filenames):
563599
"1.3.6.1.5.5.7.48.1.1": "basic-response"
564600
}
565601

602+
certIpsec_oids = {
603+
"1.3.6.1.5.5.8.2.1": "iKEEnd",
604+
"1.3.6.1.5.5.8.2.2": "iKEIntermediate",
605+
}
606+
566607
certTransp_oids = {
567608
'1.3.6.1.4.1.11129.2.4.2': "SignedCertificateTimestampList",
568609
}
@@ -724,16 +765,21 @@ def load_mib(filenames):
724765
secsig_oids,
725766
nist_oids,
726767
thawte_oids,
768+
pkcs3_oids,
727769
pkcs7_oids,
728770
pkcs9_oids,
771+
encAlgs_oids,
729772
attributeType_oids,
730773
certificateExtension_oids,
731774
certExt_oids,
732775
certPkixAd_oids,
733776
certPkixKp_oids,
777+
certPkixCmc_oids,
778+
certPkixCct_oids,
734779
certPkixPe_oids,
735780
certPkixQt_oids,
736781
certPolicy_oids,
782+
certIpsec_oids,
737783
certTransp_oids,
738784
evPolicy_oids,
739785
x962KeyType_oids,

scapy/asn1fields.py

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131
BER_tagging_enc,
3232
)
3333
from scapy.base_classes import BasePacket
34-
from scapy.compat import raw
3534
from scapy.volatile import (
3635
GeneralizedTime,
3736
RandChoice,
@@ -599,7 +598,7 @@ def build(self, pkt):
599598
elif val is None:
600599
s = b""
601600
else:
602-
s = b"".join(raw(i) for i in val)
601+
s = b"".join(bytes(i) for i in val)
603602
return self.i2m(pkt, s)
604603

605604
def i2repr(self, pkt, x):
@@ -642,6 +641,9 @@ class ASN1F_TIME_TICKS(ASN1F_INTEGER):
642641
#############################
643642

644643
class ASN1F_optional(ASN1F_element):
644+
"""
645+
ASN.1 field that is optional.
646+
"""
645647
def __init__(self, field):
646648
# type: (ASN1F_field[Any, Any]) -> None
647649
field.flexible_tag = False
@@ -682,6 +684,20 @@ def i2repr(self, pkt, x):
682684
return self._field.i2repr(pkt, x)
683685

684686

687+
class ASN1F_omit(ASN1F_field[None, None]):
688+
"""
689+
ASN.1 field that is not specified. This is simply omitted on the network.
690+
This is different from ASN1F_NULL which has a network representation.
691+
"""
692+
def m2i(self, pkt, s):
693+
# type: (ASN1_Packet, bytes) -> Tuple[None, bytes]
694+
return None, s
695+
696+
def i2m(self, pkt, x):
697+
# type: (ASN1_Packet, Optional[bytes]) -> bytes
698+
return b""
699+
700+
685701
_CHOICE_T = Union['ASN1_Packet', Type[ASN1F_field[Any, Any]], 'ASN1F_PACKET']
686702

687703

@@ -769,7 +785,7 @@ def i2m(self, pkt, x):
769785
if x is None:
770786
s = b""
771787
else:
772-
s = raw(x)
788+
s = bytes(x)
773789
if hash(type(x)) in self.pktchoices:
774790
imp, exp = self.pktchoices[hash(type(x))]
775791
s = BER_tagging_enc(s,
@@ -852,11 +868,11 @@ def i2m(self,
852868
s = x
853869
elif isinstance(x, ASN1_Object):
854870
if x.val:
855-
s = raw(x.val)
871+
s = bytes(x.val)
856872
else:
857873
s = b""
858874
else:
859-
s = raw(x)
875+
s = bytes(x)
860876
if not hasattr(x, "ASN1_root"):
861877
# A normal Packet (!= ASN1)
862878
return s
@@ -897,7 +913,7 @@ def __init__(self,
897913
self.cls = cls
898914
super(ASN1F_BIT_STRING_ENCAPS, self).__init__( # type: ignore
899915
name,
900-
default and raw(default),
916+
default and bytes(default),
901917
context=context,
902918
implicit_tag=implicit_tag,
903919
explicit_tag=explicit_tag

scapy/layers/dcerpc.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -451,6 +451,14 @@ class RPC_C_AUTHN_LEVEL(IntEnum):
451451
DCE_C_AUTHN_LEVEL = RPC_C_AUTHN_LEVEL # C706 name
452452

453453

454+
class RPC_C_IMP_LEVEL(IntEnum):
455+
DEFAULT = 0x0
456+
ANONYMOUS = 0x1
457+
IDENTIFY = 0x2
458+
IMPERSONATE = 0x3
459+
DELEGATE = 0x4
460+
461+
454462
# C706 sect 13.2.6.1
455463

456464

@@ -2766,9 +2774,9 @@ def __init__(self, *args, **kwargs):
27662774
self.ssp = kwargs.pop("ssp", None)
27672775
self.sspcontext = kwargs.pop("sspcontext", None)
27682776
self.auth_level = kwargs.pop("auth_level", None)
2769-
self.auth_context_id = kwargs.pop("auth_context_id", 0)
27702777
self.sent_cont_ids = []
27712778
self.cont_id = 0 # Currently selected context
2779+
self.auth_context_id = 0 # Currently selected authentication context
27722780
self.map_callid_opnum = {}
27732781
self.frags = collections.defaultdict(lambda: b"")
27742782
self.sniffsspcontexts = {} # Unfinished contexts for passive
@@ -3283,7 +3291,6 @@ def __init__(self, *args, **kwargs):
32833291
self.session = DceRpcSession(
32843292
ssp=kwargs.pop("ssp", None),
32853293
auth_level=kwargs.pop("auth_level", None),
3286-
auth_context_id=kwargs.pop("auth_context_id", None),
32873294
support_header_signing=kwargs.pop("support_header_signing", True),
32883295
)
32893296
super(DceRpcSocket, self).__init__(*args, **kwargs)

0 commit comments

Comments
 (0)