Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix CBT computing when cert digest algo is not MD5, SHA1 or SHA256 #1151

Open
wants to merge 1 commit into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 28 additions & 6 deletions ldap3/core/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@
from .tls import Tls
from .exceptions import LDAPUnknownStrategyError, LDAPBindError, LDAPUnknownAuthenticationMethodError, \
LDAPSASLMechanismNotSupportedError, LDAPObjectClassError, LDAPConnectionIsReadOnlyError, LDAPChangeError, LDAPExceptionError, \
LDAPObjectError, LDAPSocketReceiveError, LDAPAttributeError, LDAPInvalidValueError, LDAPInvalidPortError, LDAPStartTLSError
LDAPObjectError, LDAPSocketReceiveError, LDAPAttributeError, LDAPInvalidValueError, LDAPInvalidPortError, LDAPStartTLSError, \
LDAPPackageUnavailableError

from ..utils.conv import escape_bytes, prepare_for_stream, check_json_dict, format_json, to_unicode
from ..utils.log import log, log_enabled, ERROR, BASIC, PROTOCOL, EXTENDED, get_library_log_hide_sensitive_data
Expand Down Expand Up @@ -1400,21 +1401,41 @@ def do_ntlm_bind(self,
self.ntlm_client.confidentiality = True

if self.channel_binding == TLS_CHANNEL_BINDING:
self.ntlm_client.tls_channel_binding = True
# To perform channel binding during NTLM authentication, we need to add a new AV_PAIR (MS-NLMP 2.2.2.1)
# within the AUTHENTICATE_MESSAGE (MS-NLMP 2.2.1.3). This new AV_PAIR has AvId 0x000A (MsvAvChannelBindings).
# The Value field contains an MD5 hash of a gss_channel_bindings_struct.
# The logic here is heavly inspired by "msldap", "minikerberos" and "asysocks" projects by @skelsec.
from hashlib import sha256, md5
self.ntlm_client.tls_channel_binding = True
peer_certificate_sha256 = sha256(self.server.tls.peer_certificate).digest()

# https://datatracker.ietf.org/doc/html/rfc2744#section-3.11
# First, we need to detect which digest algorithm is used
try:
from cryptography import x509
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
except ImportError:
raise LDAPPackageUnavailableError('package cryptography missing')

peer_certificate = x509.load_der_x509_certificate(self.server.tls.peer_certificate, default_backend())
peer_certificate_hash_algorithm = peer_certificate.signature_hash_algorithm

# RFC 5929 section 4.1 hashes list
rfc5929_hashes_list = (hashes.MD5, hashes.SHA1)

# section 4.1 hash function selection
if isinstance(peer_certificate_hash_algorithm, rfc5929_hashes_list):
digest = hashes.Hash(hashes.SHA256(), default_backend())
else:
digest = hashes.Hash(peer_certificate_hash_algorithm, default_backend())
digest.update(self.server.tls.peer_certificate)
peer_certificate_digest = digest.finalize()

# Then we build the cb struct according to https://datatracker.ietf.org/doc/html/rfc2744#section-3.11
channel_binding_struct = bytes()
initiator_address = b'\x00'*8
acceptor_address = b'\x00'*8

# https://datatracker.ietf.org/doc/html/rfc5929#section-4
application_data_raw = b'tls-server-end-point:' + peer_certificate_sha256
application_data_raw = b'tls-server-end-point:' + peer_certificate_digest
len_application_data = len(application_data_raw).to_bytes(4, byteorder='little', signed = False)
application_data = len_application_data
application_data += application_data_raw
Expand All @@ -1424,6 +1445,7 @@ def do_ntlm_bind(self,

# https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-nlmp/83f5e789-660d-4781-8491-5f8c6641f75e
# "The Value field contains an MD5 hash of a gss_channel_bindings_struct"
from hashlib import md5
self.ntlm_client.client_av_channel_bindings = md5(channel_binding_struct).digest()

# as per https://msdn.microsoft.com/en-us/library/cc223501.aspx
Expand Down
3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pyasn1>=0.4.6
pycryptodomex
winkerberos
winkerberos
cryptography