From 09261f05d513183df12a184f0c01f3fd2044f208 Mon Sep 17 00:00:00 2001 From: seladb Date: Fri, 14 Jun 2024 19:27:44 -0700 Subject: [PATCH] Add LDAP bind and unbind messages (#1448) --- Common++/header/PointerVector.h | 5 + Packet++/header/LdapLayer.h | 254 ++++++++++++++++- Packet++/src/Asn1Codec.cpp | 15 +- Packet++/src/LdapLayer.cpp | 205 +++++++++++++- Tests/Packet++Test/PacketExamples/ldap.pcapng | Bin 7488 -> 8056 bytes .../PacketExamples/ldap_bind_request2.dat | 1 + .../PacketExamples/ldap_bind_response1.dat | 1 + .../PacketExamples/ldap_bind_response2.dat | 1 + .../PacketExamples/ldap_unbind_request.dat | 1 + Tests/Packet++Test/Tests/Asn1Tests.cpp | 14 +- Tests/Packet++Test/Tests/LdapTests.cpp | 257 ++++++++++++++++++ 11 files changed, 732 insertions(+), 22 deletions(-) create mode 100644 Tests/Packet++Test/PacketExamples/ldap_bind_request2.dat create mode 100644 Tests/Packet++Test/PacketExamples/ldap_bind_response1.dat create mode 100644 Tests/Packet++Test/PacketExamples/ldap_bind_response2.dat create mode 100644 Tests/Packet++Test/PacketExamples/ldap_unbind_request.dat diff --git a/Common++/header/PointerVector.h b/Common++/header/PointerVector.h index 50014390af..d73d60238f 100644 --- a/Common++/header/PointerVector.h +++ b/Common++/header/PointerVector.h @@ -138,6 +138,11 @@ namespace pcpp */ T* front() { return m_Vector.front(); } + /** + * @return A pointer to the last element in the vector + */ + T* back() { return m_Vector.back(); } + /** * Removes from the vector a single element (position). Once the element is erased, it's also freed * @param[in] position The position of the element to erase diff --git a/Packet++/header/LdapLayer.h b/Packet++/header/LdapLayer.h index 6a5e8c4f46..92751cecd5 100644 --- a/Packet++/header/LdapLayer.h +++ b/Packet++/header/LdapLayer.h @@ -430,7 +430,7 @@ namespace pcpp /** * @return The LDAP operation of this message. If the Operation ASN.1 record is malformed, an exception is thrown */ - LdapOperationType getLdapOperationType() const; + virtual LdapOperationType getLdapOperationType() const; /** * Most getter methods in this class throw an exception if the corresponding ASN.1 record is invalid. @@ -561,17 +561,221 @@ namespace pcpp static constexpr uint8_t referralTagType = 3; + LdapResponseLayer() = default; LdapResponseLayer(std::unique_ptr asn1Record, uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) : LdapLayer(std::move(asn1Record), data, dataLen, prevLayer, packet) {} - LdapResponseLayer(uint16_t messageId, const LdapOperationType& operationType, const LdapResultCode& resultCode, + LdapResponseLayer(uint16_t messageId, LdapOperationType operationType, LdapResultCode resultCode, const std::string& matchedDN, const std::string& diagnosticMessage, const std::vector& referral = std::vector(), const std::vector& controls = std::vector()); + void init(uint16_t messageId, LdapOperationType operationType, LdapResultCode resultCode, + const std::string& matchedDN, const std::string& diagnosticMessage, + const std::vector& referral = std::vector(), + const std::vector& additionalRecords = std::vector(), + const std::vector& controls = std::vector()); + std::string getExtendedInfoString() const override; }; + /** + * @class LdapBindRequestLayer + * Represents LDAP bind request operation + */ + class LdapBindRequestLayer : public LdapLayer + { + public: + /** + * An enum to represent the bind request authentication type + */ + enum class AuthenticationType : uint8_t + { + /// Simple authentication + Simple = 0, + /// SASL authentication + Sasl = 3, + /// Unknown / not application authentication type + NotApplicable = 255 + }; + + /** + * @struct SaslAuthentication + * A struct to represent SASL authentication + */ + struct SaslAuthentication + { + /// The SASL mechanism + std::string mechanism; + /// Encoded SASL credentials + std::vector credentials; + + /** + * Equality operator overload for this struct + * @param[in] other The value to compare with + * @return True if both values are equal, false otherwise + */ + bool operator==(const SaslAuthentication& other) const + { + return mechanism == other.mechanism && credentials == other.credentials; + } + + /** + * Inequality operator overload for this struct + * @param[in] other The value to compare with + * @return False if both values are equal, true otherwise + */ + bool operator!=(const SaslAuthentication& other) const + { + return !operator==(other); + } + }; + + /** + * A constructor to create a new LDAP bind request message with simple authentication + * @param[in] messageId The LDAP message ID + * @param[in] version The LDAP protocol version that the client wants to use + * @param[in] name The DN of the user to authenticate + * @param[in] simpleAuthentication Simple authentication to use in this message + * @param[in] controls A vector of LDAP controls. This is an optional parameter, if not provided the message + * will be created without LDAP controls + */ + LdapBindRequestLayer( + uint16_t messageId, uint8_t version, const std::string& name, const std::string& simpleAuthentication, + const std::vector& controls = std::vector()); + + /** + * A constructor to create a new LDAP bind request message with SASL authentication + * @param[in] messageId The LDAP message ID + * @param[in] version The LDAP protocol version that the client wants to use + * @param[in] name The DN of the user to authenticate + * @param[in] saslAuthentication SASL authentication to use in this message + * @param[in] controls A vector of LDAP controls. This is an optional parameter, if not provided the message + * will be created without LDAP controls + */ + LdapBindRequestLayer( + uint16_t messageId, uint8_t version, const std::string& name, const SaslAuthentication& saslAuthentication, + const std::vector& controls = std::vector()); + + /** + * @return The LDAP protocol version that the client wants to use + */ + uint32_t getVersion() const; + + /** + * @return The DN of the user to authenticate + */ + std::string getName() const; + + /** + * @return The authentication type included in this message + */ + AuthenticationType getAuthenticationType() const; + + /** + * @return The simple authentication included in this message + * @throws std::invalid_argument if the message doesn't include simple authentication + */ + std::string getSimpleAuthentication() const; + + /** + * @return The SASL authentication included in this message + * @throws std::invalid_argument if the message doesn't include SASL authentication + */ + SaslAuthentication getSaslAuthentication() const; + + template + bool tryGet(Method method, ResultType& result) + { + return internalTryGet(this, method, result); + } + protected: + friend LdapLayer* LdapLayer::parseLdapMessage(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet); + + LdapBindRequestLayer(std::unique_ptr asn1Record, uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) + : LdapLayer(std::move(asn1Record), data, dataLen, prevLayer, packet) {} + + std::string getExtendedInfoString() const override; + private: + static constexpr int versionIndex = 0; + static constexpr int nameIndex = 1; + static constexpr int credentialIndex = 2; + + static constexpr int saslMechanismIndex = 0; + static constexpr int saslCredentialsIndex = 1; + }; + + /** + * @class LdapBindResponseLayer + * Represents LDAP bind response operation + */ + class LdapBindResponseLayer : public LdapResponseLayer + { + public: + /** + * A constructor to create a new LDAP bind response message + * @param[in] messageId The LDAP message ID + * @param[in] resultCode The LDAP result code + * @param[in] matchedDN The distinguished name (DN) to set on the message. If not applicable + * pass an empty string + * @param[in] diagnosticMessage The additional information to set on the message. If not applicable + * pass an empty string + * @param[in] referral A list of URIs to re-try the operation somewhere else. This is an optional + * parameter. If not provided then referral won't be added to the message + * @param[in] serverSaslCredentials Encoded server SASL credentials for use in subsequent processing + * @param[in] controls A vector of LDAP controls. This is an optional parameter, if not provided the message + * will be created without LDAP controls + */ + LdapBindResponseLayer(uint16_t messageId, LdapResultCode resultCode, const std::string& matchedDN, + const std::string& diagnosticMessage, const std::vector& referral = std::vector(), + const std::vector& serverSaslCredentials = std::vector(), + const std::vector& controls = std::vector()); + + /** + * @return Encoded server SASL credentials for use in subsequent processing + */ + std::vector getServerSaslCredentials() const; + protected: + friend LdapLayer* LdapLayer::parseLdapMessage(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet); + + static constexpr int serverSaslCredentialsTagType = 7; + + LdapBindResponseLayer(std::unique_ptr asn1Record, uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) + : LdapResponseLayer(std::move(asn1Record), data, dataLen, prevLayer, packet) {} + }; + + /** + * @class LdapUnbindRequestLayer + * Represents LDAP unbind operation + */ + class LdapUnbindRequestLayer : public LdapLayer + { + public: + /** + * A constructor to create a new LDAP unbind message + * @param[in] messageId The LDAP message ID + * @param[in] controls A vector of LDAP controls. This is an optional parameter, if not provided the message + * will be created without LDAP controls + */ + explicit LdapUnbindRequestLayer(uint16_t messageId, const std::vector& controls = std::vector()); + + // Unbind request has no operation record + Asn1ConstructedRecord* getLdapOperationAsn1Record() const = delete; + + LdapOperationType getLdapOperationType() const override { return LdapOperationType::UnbindRequest; } + + template + bool tryGet(Method method, ResultType& result) + { + return internalTryGet(this, method, result); + } + protected: + friend LdapLayer* LdapLayer::parseLdapMessage(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet); + + LdapUnbindRequestLayer(std::unique_ptr asn1Record, uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) + : LdapLayer(std::move(asn1Record), data, dataLen, prevLayer, packet) {} + }; + /** * @class LdapSearchRequestLayer * Represents LDAP search request operation @@ -864,7 +1068,7 @@ namespace pcpp * @param[in] controls A vector of LDAP controls. This is an optional parameter, if not provided the message * will be created without LDAP controls */ - LdapSearchResultDoneLayer(uint16_t messageId, const LdapResultCode& resultCode, const std::string& matchedDN, + LdapSearchResultDoneLayer(uint16_t messageId, LdapResultCode resultCode, const std::string& matchedDN, const std::string& diagnosticMessage, const std::vector& referral = std::vector(), const std::vector& controls = std::vector()) : LdapResponseLayer(messageId, LdapOperationType::SearchResultDone, resultCode, matchedDN, diagnosticMessage, referral, controls) {} @@ -895,7 +1099,7 @@ namespace pcpp * @param[in] controls A vector of LDAP controls. This is an optional parameter, if not provided the message * will be created without LDAP controls */ - LdapModifyResponseLayer(uint16_t messageId, const LdapResultCode& resultCode, const std::string& matchedDN, + LdapModifyResponseLayer(uint16_t messageId, LdapResultCode resultCode, const std::string& matchedDN, const std::string& diagnosticMessage, const std::vector& referral = std::vector(), const std::vector& controls = std::vector()) : LdapResponseLayer(messageId, LdapOperationType::ModifyResponse, resultCode, matchedDN, diagnosticMessage, referral, controls) {} @@ -926,7 +1130,7 @@ namespace pcpp * @param[in] controls A vector of LDAP controls. This is an optional parameter, if not provided the message * will be created without LDAP controls */ - LdapAddResponseLayer(uint16_t messageId, const LdapResultCode& resultCode, const std::string& matchedDN, + LdapAddResponseLayer(uint16_t messageId, LdapResultCode resultCode, const std::string& matchedDN, const std::string& diagnosticMessage, const std::vector& referral = std::vector(), const std::vector& controls = std::vector()) : LdapResponseLayer(messageId, LdapOperationType::AddResponse, resultCode, matchedDN, diagnosticMessage, referral, controls) {} @@ -957,7 +1161,7 @@ namespace pcpp * @param[in] controls A vector of LDAP controls. This is an optional parameter, if not provided the message * will be created without LDAP controls */ - LdapDeleteResponseLayer(uint16_t messageId, const LdapResultCode& resultCode, const std::string& matchedDN, + LdapDeleteResponseLayer(uint16_t messageId, LdapResultCode resultCode, const std::string& matchedDN, const std::string& diagnosticMessage, const std::vector& referral = std::vector(), const std::vector& controls = std::vector()) : LdapResponseLayer(messageId, LdapOperationType::DeleteResponse, resultCode, matchedDN, diagnosticMessage, referral, controls) {} @@ -988,7 +1192,7 @@ namespace pcpp * @param[in] controls A vector of LDAP controls. This is an optional parameter, if not provided the message * will be created without LDAP controls */ - LdapModifyDNResponseLayer(uint16_t messageId, const LdapResultCode& resultCode, const std::string& matchedDN, + LdapModifyDNResponseLayer(uint16_t messageId, LdapResultCode resultCode, const std::string& matchedDN, const std::string& diagnosticMessage, const std::vector& referral = std::vector(), const std::vector& controls = std::vector()) : LdapResponseLayer(messageId, LdapOperationType::ModifyDNResponse, resultCode, matchedDN, diagnosticMessage, referral, controls) {} @@ -1019,7 +1223,7 @@ namespace pcpp * @param[in] controls A vector of LDAP controls. This is an optional parameter, if not provided the message * will be created without LDAP controls */ - LdapCompareResponseLayer(uint16_t messageId, const LdapResultCode& resultCode, const std::string& matchedDN, + LdapCompareResponseLayer(uint16_t messageId, LdapResultCode resultCode, const std::string& matchedDN, const std::string& diagnosticMessage, const std::vector& referral = std::vector(), const std::vector& controls = std::vector()) : LdapResponseLayer(messageId, LdapOperationType::CompareResponse, resultCode, matchedDN, diagnosticMessage, referral, controls) {} @@ -1039,14 +1243,36 @@ inline std::ostream& operator<<(std::ostream& os, const pcpp::LdapControl& contr inline std::ostream& operator<<(std::ostream& os, const pcpp::LdapAttribute& attr) { - std::string valuesStream; - bool first = true; + os << "{" << attr.type << ", {"; + + std::string separator; for (const auto& value : attr.values) { - if (!first) valuesStream += ", "; - valuesStream += value; - first = false; + os << separator << value; + if (separator.empty()) + { + separator = ", "; + } } - os << "{" << attr.type << ", {" << valuesStream << "}}"; + + os << "}}"; + return os; +} + +inline std::ostream& operator<<(std::ostream& os, const pcpp::LdapBindRequestLayer::SaslAuthentication& saslAuthentication) +{ + os << "{" << saslAuthentication.mechanism << ", {"; + + std::string separator; + for (const auto& value : saslAuthentication.credentials) + { + os << separator << "0x" << std::hex << static_cast(value) << std::dec; + if (separator.empty()) + { + separator = ", "; + } + } + + os << "}}"; return os; } diff --git a/Packet++/src/Asn1Codec.cpp b/Packet++/src/Asn1Codec.cpp index 98855989b0..e1c07d61b3 100644 --- a/Packet++/src/Asn1Codec.cpp +++ b/Packet++/src/Asn1Codec.cpp @@ -142,10 +142,19 @@ namespace pcpp return result; } - // Assuming the size is always less than 256 - uint8_t firstByte = 0x80 | 0x01; + auto tempValueLength = m_ValueLength; + do + { + uint8_t byte = tempValueLength & 0xff; + result.push_back(byte); // Inserts the bytes in reverse order + tempValueLength >>= 8; + } while (tempValueLength != 0); + + uint8_t firstByte = 0x80 | static_cast(result.size()); result.push_back(firstByte); - result.push_back(m_ValueLength); + + // Reverses the bytes to get forward ordering + std::reverse(result.begin(), result.end()); return result; } diff --git a/Packet++/src/LdapLayer.cpp b/Packet++/src/LdapLayer.cpp index 7eff2c7821..5874c2a5e5 100644 --- a/Packet++/src/LdapLayer.cpp +++ b/Packet++/src/LdapLayer.cpp @@ -193,9 +193,17 @@ namespace pcpp { void LdapLayer::init(uint16_t messageId, LdapOperationType operationType, const std::vector& messageRecords, const std::vector& controls) { Asn1IntegerRecord messageIdRecord(messageId); - Asn1ConstructedRecord messageRootRecord(Asn1TagClass::Application, operationType, messageRecords); + std::unique_ptr messageRootRecord; + if (!messageRecords.empty()) + { + messageRootRecord = std::unique_ptr(new Asn1ConstructedRecord(Asn1TagClass::Application, operationType, messageRecords)); + } + else + { + messageRootRecord = std::unique_ptr(new Asn1GenericRecord(Asn1TagClass::Application, false, operationType, "")); + } - std::vector rootSubRecords = {&messageIdRecord, &messageRootRecord}; + std::vector rootSubRecords = {&messageIdRecord, messageRootRecord.get()}; std::unique_ptr controlsRecord; if (!controls.empty()) @@ -245,6 +253,12 @@ namespace pcpp { auto operationType = LdapOperationType::fromUintValue(asn1Record->castAs()->getSubRecords().at(operationTypeIndex)->getTagType()); switch (operationType) { + case LdapOperationType::BindRequest: + return new LdapBindRequestLayer(std::move(asn1Record), data, dataLen, prevLayer, packet); + case LdapOperationType::BindResponse: + return new LdapBindResponseLayer(std::move(asn1Record), data, dataLen, prevLayer, packet); + case LdapOperationType::UnbindRequest: + return new LdapUnbindRequestLayer(std::move(asn1Record), data, dataLen, prevLayer, packet); case LdapOperationType::SearchRequest: return new LdapSearchRequestLayer(std::move(asn1Record), data, dataLen, prevLayer, packet); case LdapOperationType::SearchResultEntry: @@ -332,9 +346,16 @@ namespace pcpp { // region LdapResponseLayer - LdapResponseLayer::LdapResponseLayer(uint16_t messageId, const LdapOperationType& operationType, const LdapResultCode& resultCode, + LdapResponseLayer::LdapResponseLayer(uint16_t messageId, LdapOperationType operationType, LdapResultCode resultCode, const std::string& matchedDN, const std::string& diagnosticMessage, const std::vector& referral, const std::vector& controls) + { + LdapResponseLayer::init(messageId, operationType, resultCode, matchedDN, diagnosticMessage, referral, {}, controls); + } + + void LdapResponseLayer::init(uint16_t messageId, LdapOperationType operationType, LdapResultCode resultCode, + const std::string& matchedDN, const std::string& diagnosticMessage, const std::vector& referral, + const std::vector& additionalRecords, const std::vector& controls) { Asn1EnumeratedRecord resultCodeRecord(resultCode); Asn1OctetStringRecord matchedDNRecord(matchedDN); @@ -351,10 +372,18 @@ namespace pcpp { referralSubRecords.pushBack(new Asn1OctetStringRecord(uri)); } referralRecord = std::unique_ptr(new Asn1ConstructedRecord( - Asn1TagClass::ContextSpecific, referralTagType, referralSubRecords)); + Asn1TagClass::ContextSpecific, referralTagType, referralSubRecords)); messageRecords.push_back(referralRecord.get()); } + if (!additionalRecords.empty()) + { + for (auto additionalRecord : additionalRecords) + { + messageRecords.push_back(additionalRecord); + } + } + LdapLayer::init(messageId, operationType, messageRecords, controls); } @@ -401,6 +430,174 @@ namespace pcpp { } // endregion + // region LdapBindRequestLayer + + LdapBindRequestLayer::LdapBindRequestLayer( + uint16_t messageId, uint8_t version, const std::string& name, const std::string& simpleAuthentication, + const std::vector& controls) + { + Asn1IntegerRecord versionRecord(version); + Asn1OctetStringRecord nameRecord(name); + std::vector messageRecords = {&versionRecord, &nameRecord}; + std::unique_ptr simpleAuthenticationRecord; + if (!simpleAuthentication.empty()) + { + auto data = reinterpret_cast(simpleAuthentication.data()); + simpleAuthenticationRecord = std::unique_ptr( + new Asn1GenericRecord(Asn1TagClass::ContextSpecific, false, static_cast(LdapBindRequestLayer::AuthenticationType::Simple), data, simpleAuthentication.size())); + messageRecords.push_back(simpleAuthenticationRecord.get()); + } + + LdapLayer::init(messageId, LdapOperationType::BindRequest, messageRecords, controls); + } + + LdapBindRequestLayer::LdapBindRequestLayer( + uint16_t messageId, uint8_t version, const std::string& name, const SaslAuthentication& saslAuthentication, + const std::vector& controls) + { + Asn1IntegerRecord versionRecord(version); + Asn1OctetStringRecord nameRecord(name); + std::vector messageRecords = {&versionRecord, &nameRecord}; + std::unique_ptr saslAuthenticationRecord; + if (!saslAuthentication.mechanism.empty()) + { + PointerVector saslAuthenticationRecords; + saslAuthenticationRecords.pushBack(new Asn1OctetStringRecord(saslAuthentication.mechanism)); + if (!saslAuthentication.credentials.empty()) + { + auto credentialsRecord = new Asn1OctetStringRecord(saslAuthentication.credentials.data(), saslAuthentication.credentials.size()); + saslAuthenticationRecords.pushBack(credentialsRecord); + } + + saslAuthenticationRecord = std::unique_ptr( + new Asn1ConstructedRecord(Asn1TagClass::ContextSpecific, static_cast(LdapBindRequestLayer::AuthenticationType::Sasl), saslAuthenticationRecords)); + messageRecords.push_back(saslAuthenticationRecord.get()); + } + + LdapLayer::init(messageId, LdapOperationType::BindRequest, messageRecords, controls); + } + + uint32_t LdapBindRequestLayer::getVersion() const + { + return getLdapOperationAsn1Record()->getSubRecords().at(versionIndex)->castAs()->getValue(); + } + + std::string LdapBindRequestLayer::getName() const + { + return getLdapOperationAsn1Record()->getSubRecords().at(nameIndex)->castAs()->getValue(); + } + + LdapBindRequestLayer::AuthenticationType LdapBindRequestLayer::getAuthenticationType() const + { + if (getLdapOperationAsn1Record()->getSubRecords().size() <= credentialIndex) + { + return LdapBindRequestLayer::AuthenticationType::NotApplicable; + } + + auto authType = getLdapOperationAsn1Record()->getSubRecords().at(credentialIndex)->getTagType(); + switch (authType) + { + case 0: + return LdapBindRequestLayer::AuthenticationType::Simple; + case 3: + return LdapBindRequestLayer::AuthenticationType::Sasl; + default: + return LdapBindRequestLayer::AuthenticationType::NotApplicable; + } + } + + std::string LdapBindRequestLayer::getSimpleAuthentication() const + { + if (getAuthenticationType() != LdapBindRequestLayer::AuthenticationType::Simple) + { + throw std::invalid_argument("Authentication type is not simple"); + } + + auto authRecord = getLdapOperationAsn1Record()->getSubRecords().at(credentialIndex)->castAs(); + return {reinterpret_cast(authRecord->getValue()), authRecord->getValueLength()}; + } + + LdapBindRequestLayer::SaslAuthentication LdapBindRequestLayer::getSaslAuthentication() const + { + if (getAuthenticationType() != LdapBindRequestLayer::AuthenticationType::Sasl) + { + throw std::invalid_argument("Authentication type is not sasl"); + } + + auto authRecord = getLdapOperationAsn1Record()->getSubRecords().at(credentialIndex)->castAs(); + std::string mechanism; + std::vector credentials; + if (authRecord->getSubRecords().size() > saslMechanismIndex) + { + mechanism = authRecord->getSubRecords().at(saslMechanismIndex)->castAs()->getValue(); + } + if (authRecord->getSubRecords().size() > saslCredentialsIndex) + { + auto credentialsAsString = authRecord->getSubRecords().at(saslCredentialsIndex)->castAs()->getValue(); + credentials.resize(credentialsAsString.size() / 2); + hexStringToByteArray(credentialsAsString, credentials.data(), credentials.size()); + } + + return {mechanism, credentials}; + } + + std::string LdapBindRequestLayer::getExtendedInfoString() const + { + switch (getAuthenticationType()) + { + case AuthenticationType::Simple: + return "simple"; + case AuthenticationType::Sasl: + return "sasl"; + default: + return "Unknown"; + } + } + + // endregion + + // region LdapBindResponseLayer + + LdapBindResponseLayer::LdapBindResponseLayer(uint16_t messageId, LdapResultCode resultCode, + const std::string& matchedDN, const std::string& diagnosticMessage, + const std::vector& referral, const std::vector& serverSaslCredentials, + const std::vector& controls) + { + std::vector additionalRecords; + std::unique_ptr serverSaslCredentialsRecord; + if (!serverSaslCredentials.empty()) + { + serverSaslCredentialsRecord = std::unique_ptr(new Asn1GenericRecord(Asn1TagClass::ContextSpecific, false, serverSaslCredentialsTagType, serverSaslCredentials.data(), serverSaslCredentials.size())); + additionalRecords.push_back(serverSaslCredentialsRecord.get()); + } + + LdapResponseLayer::init(messageId, LdapOperationType::BindResponse, resultCode, matchedDN, diagnosticMessage, referral, additionalRecords, controls); + } + + std::vector LdapBindResponseLayer::getServerSaslCredentials() const + { + try + { + auto serverSaslCredentialsRecord = getLdapOperationAsn1Record()->getSubRecords().back()->castAs(); + return {serverSaslCredentialsRecord->getValue(), serverSaslCredentialsRecord->getValue() + serverSaslCredentialsRecord->getValueLength()}; + } + catch (const std::exception&) + { + return {}; + } + } + + // endregion + + // region LdapUnbindRequestLayer + + LdapUnbindRequestLayer::LdapUnbindRequestLayer(uint16_t messageId, const std::vector& controls) + { + LdapLayer::init(messageId, LdapOperationType::UnbindRequest, {}, controls); + } + + // endregion + // region LdapSearchRequestLayer const std::unordered_map> SearchRequestScopeToString { diff --git a/Tests/Packet++Test/PacketExamples/ldap.pcapng b/Tests/Packet++Test/PacketExamples/ldap.pcapng index 7170751cd0526ff3c26c2faab6375c5e69fef67e..3637e9192ad37765f407a45cedb197e3898327e0 100644 GIT binary patch delta 549 zcmX?L^}}w%55~z2j1rRz7-d-Rure@+Z2rpV&Rs9T$iTqKz`(HTH8aDSdrJOafou?F z;L-e$eGy1<`u^fzaAjb4&X(@L(7-lh-WqwvR3Oe^Y~|6Z)BRLCwet6}0Eu58DiRqO z3|fFXcQP?CTu%hC)^jm3umE9u6T^~)jSCGL=Ph6c3N7SjCg29 zvOyRbfJ4T5lCT4V1KXzCI*Jh(tN7?03&gnIRF3v delta 21 dcmexicfe}H55~?5GV4*+g^2+;rl diff --git a/Tests/Packet++Test/PacketExamples/ldap_bind_request2.dat b/Tests/Packet++Test/PacketExamples/ldap_bind_request2.dat new file mode 100644 index 0000000000..29dbe8bf1d --- /dev/null +++ b/Tests/Packet++Test/PacketExamples/ldap_bind_request2.dat @@ -0,0 +1 @@ +000c29094dfa005056c00001080045000570437740007e0645e1c0a80003ac1f01650fe20185e5eb721da044ead55018faf0ffa300003084000005420201076084000005390201030400a3840000052e040a4753532d53504e45474f0482051e6082051a06062b0601050502a082050e3082050aa024302206092a864882f71201020206092a864886f712010202060a2b06010401823702020aa28204e0048204dc608204d806092a864886f71201020201006e8204c7308204c3a003020105a10302010ea20703050020000000a38203e0618203dc308203d8a003020105a1151b1357324b332e564d4e4554312e564d2e42415345a22f302da003020102a12630241b046c6461701b1c77326b332d3130312e77326b332e766d6e6574312e766d2e62617365a382038730820383a003020117a103020107a2820375048203716a61c886ba58d162113db4268f7743a17eb476183bc0c519addea76556a3701de34903e6bd3f3fdca0b01bbccb9a8693b23fa8d1985e14922e4ca19b05a90769845a5858515bba4af2d7e59bfa8634285a2e954fb518378b8d3f2744b9bbf8842b4807879ff28e55bfba4967e8c1d3b6c4e358a561c54abbc1cb7c97b6503fe59b7fee6423dffe66fe6dcb8af00e69c53d6b576f5506990438310fb7dd1468a32fd8e0deab40b15ecfd438568370140a1edafee701a4a4b4e7b3aaefdc4b1aff5868aefe5a36294d5dd687d5a6493143d3ade8031c98d28f6c7f3dcea41435132f675f26940d1f69e573e5ece6ed5a66111ff9f4b02a8ddd19086e5b9dc0adc86a0bc1230f1b715ffc4004dfc4a7d5f78a4dc31abf830ae6e3bfd21c87fa5196549e130f6a081bafcf4170ae201c78a3829a01dba578a2ef968f2ab6668d8114dfcc65d7038f5558be7cdd9246d52247915260a40e59c48b08a1ed61427fd303917c6b34b701a4ba9a3815d4828a228cd209da137626e2029aabf6c200bf7fd63cf6d43bb618b31ac48e09613589d74a69542e909ce0dc9c57c77f7d89b966de200053a58ea58f2374513961638a30ca49ef0eec679d927e385b5da7d4d3c1a59169b4630b874a1d969e45d1fe3782089f4385024955093b308e1964d307915271aa886c3d9b64d846c88ca1341fd2f72b76679d4f258f647bc04820e42776c9ec0d01464652763a49d822c9d25b603903ebd6338952259b83a740a420d69d23aebbdf06a92d88a46ffcd8d81a47b6ec99b6cea0489cc83ef15757c4053d538446f2e6b9eba12ce4969b8d6df9b3ef574b7d401341c2f555a00f029164e5d387282c0c8791ba8c69816248e2e544a9c12b7aeba629fdeea2e111655e44b9c215924c5455eaa4ab32aea1d9cef1d86e8acf6b0ff4dcabaf4f0e2d9ae65c8bb1065e0418ff12d4626930315938bfe00a8d03e8e70e9dea9dc9ff74854cbb4dbdf700a62e77b26e50b13e2d3960c913360c84c87e801ed3df3db0e27604508cb730c5a052c068abe5826b01be9f62e33b9af8edb6667c57cb1aa879743b77a7432f75fe3ae211f96af41adef1e1c507256fe5fa2bccabe52cf8216d3410e6378506d427343458332d153a77a162c4c5f18d9f31b0c142880cad2229981720615ab26b7c13442e43178aadee436510c91bc9d5d735eb9453cf39cef5120e28603775f0483f01c3c48b5b060ca7f3a54d7c7c99a481c93081c6a003020117a281be0481bb03ab656760a3512fecc7032da8b2014659f0fb34eb76b461e4044da24d16d458e3e1c58919c74c4c0720aafb87a948152372a2483a4d1ae9b95b858a52abaa94e7aa641a8b997d7e6c6e570b5908cc549155f5e6f110c98d648978727abae3921da52a4c1fd76beb121bf3396be8f98e4acf1ebfc3b6fb7a1354c121873e59185db90030084d97864798d79eb9df30756ca1faa7a80880f74f7d93642d9ceb5e0128ced6ab096a4f015e5a032b4270231e7ff1bcd087e8b527027d \ No newline at end of file diff --git a/Tests/Packet++Test/PacketExamples/ldap_bind_response1.dat b/Tests/Packet++Test/PacketExamples/ldap_bind_response1.dat new file mode 100644 index 0000000000..c495197eaa --- /dev/null +++ b/Tests/Packet++Test/PacketExamples/ldap_bind_response1.dat @@ -0,0 +1 @@ +000c29f06bd1000c29094dfa0800450000e7066740008006989eac1f0165ac1f016801850c2c7e2df27d9579fba65018faf0786100003084000000b9020200d76184000000af0a010004000400878200a4a181a130819ea0030a0100a10b06092a864882f712010202a2818904818660818306092a864886f71201020202006f743072a003020105a10302010fa2663064a003020117a25d045b4a9f10ab8996fa43f2fb4092a76cc3fa6c1f001167fac904dab067f5f2da59a7549057bd3eb46cb467fd3b01d73f5051aa632ed8d6a6e581bbab1780faabac515284139cfb44c204ae1ec25a2d58909d22ff52349e6d2e4d835b98 \ No newline at end of file diff --git a/Tests/Packet++Test/PacketExamples/ldap_bind_response2.dat b/Tests/Packet++Test/PacketExamples/ldap_bind_response2.dat new file mode 100644 index 0000000000..a846485228 --- /dev/null +++ b/Tests/Packet++Test/PacketExamples/ldap_bind_response2.dat @@ -0,0 +1 @@ +000c29a01b43000c2932503f08004500004a396d400080063ae8c0a80283c0a80285018586118f18ef87d911238b80180103142200000101080a008b457100dbc8753084000000100201026184000000070a010004000400 \ No newline at end of file diff --git a/Tests/Packet++Test/PacketExamples/ldap_unbind_request.dat b/Tests/Packet++Test/PacketExamples/ldap_unbind_request.dat new file mode 100644 index 0000000000..c6199026c5 --- /dev/null +++ b/Tests/Packet++Test/PacketExamples/ldap_unbind_request.dat @@ -0,0 +1 @@ +00000000000000000000000008004500003b921340004006aaa77f0000017f0000019e690185dcda66aedcbdd52c80182000fe2f00000101080a2fc0f4582fc0f45830050201034200 \ No newline at end of file diff --git a/Tests/Packet++Test/Tests/Asn1Tests.cpp b/Tests/Packet++Test/Tests/Asn1Tests.cpp index 7b650f86f9..03b8d3264c 100644 --- a/Tests/Packet++Test/Tests/Asn1Tests.cpp +++ b/Tests/Packet++Test/Tests/Asn1Tests.cpp @@ -381,7 +381,7 @@ PTF_TEST_CASE(Asn1EncodingTest) PTF_ASSERT_BUF_COMPARE(encodedValue.data(), data, dataLen) } - // Long length + // Record length > 128 { pcpp::Asn1OctetStringRecord record("12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"); @@ -393,6 +393,18 @@ PTF_TEST_CASE(Asn1EncodingTest) PTF_ASSERT_BUF_COMPARE(encodedValue.data(), data, dataLen) } + // Record length > 256 + { + pcpp::Asn1OctetStringRecord record("012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"); + + uint8_t data[304]; + auto dataLen = pcpp::hexStringToByteArray("0482012c303132333435363738393031323334353637383930313233343536373839303132333435363738393031323334353637383930313233343536373839303132333435363738393031323334353637383930313233343536373839303132333435363738393031323334353637383930313233343536373839303132333435363738393031323334353637383930313233343536373839303132333435363738393031323334353637383930313233343536373839303132333435363738393031323334353637383930313233343536373839303132333435363738393031323334353637383930313233343536373839303132333435363738393031323334353637383930313233343536373839303132333435363738393031323334353637383930313233343536373839", data, 304); + + auto encodedValue = record.encode(); + PTF_ASSERT_EQUAL(encodedValue.size(), dataLen); + PTF_ASSERT_BUF_COMPARE(encodedValue.data(), data, dataLen) + } + // Integer 1 byte { pcpp::Asn1IntegerRecord record(6); diff --git a/Tests/Packet++Test/Tests/LdapTests.cpp b/Tests/Packet++Test/Tests/LdapTests.cpp index 1ade15bc34..e57f5b2aab 100644 --- a/Tests/Packet++Test/Tests/LdapTests.cpp +++ b/Tests/Packet++Test/Tests/LdapTests.cpp @@ -105,6 +105,132 @@ PTF_TEST_CASE(LdapParsingTest) PTF_ASSERT_NULL(ldapLayer->getNextLayer()); } + // BindRequest with simple authentication + { + READ_FILE_AND_CREATE_PACKET(1, "PacketExamples/ldap_bind_request1.dat"); + pcpp::Packet bindRequestPacket(&rawPacket1); + + auto bindRequestLayer = bindRequestPacket.getLayerOfType(); + PTF_ASSERT_NOT_NULL(bindRequestLayer); + PTF_ASSERT_EQUAL(bindRequestLayer->getMessageID(), 2); + PTF_ASSERT_EQUAL(bindRequestLayer->getLdapOperationType(), pcpp::LdapOperationType::BindRequest, enum); + PTF_ASSERT_EQUAL(bindRequestLayer->getVersion(), 3); + PTF_ASSERT_EQUAL(bindRequestLayer->getName(), "cn=Administrator,cn=Users,dc=cloudshark-a,dc=example,dc=com"); + PTF_ASSERT_EQUAL(bindRequestLayer->getAuthenticationType(), pcpp::LdapBindRequestLayer::AuthenticationType::Simple, enumclass); + PTF_ASSERT_EQUAL(bindRequestLayer->getSimpleAuthentication(), "cloudshark123!"); + PTF_ASSERT_RAISES(bindRequestLayer->getSaslAuthentication(), std::invalid_argument, "Authentication type is not sasl"); + pcpp::LdapBindRequestLayer::SaslAuthentication saslAuthentication; + PTF_ASSERT_FALSE(bindRequestLayer->tryGet(&pcpp::LdapBindRequestLayer::getSaslAuthentication, saslAuthentication)); + PTF_ASSERT_EQUAL(bindRequestLayer->toString(), "LDAP Layer, BindRequest, simple"); + } + + // BindRequest with sasl authentication + { + READ_FILE_AND_CREATE_PACKET(1, "PacketExamples/ldap_bind_request2.dat"); + pcpp::Packet bindRequestPacket(&rawPacket1); + + auto bindRequestLayer = bindRequestPacket.getLayerOfType(); + PTF_ASSERT_NOT_NULL(bindRequestLayer); + PTF_ASSERT_EQUAL(bindRequestLayer->getMessageID(), 7); + PTF_ASSERT_EQUAL(bindRequestLayer->getLdapOperationType(), pcpp::LdapOperationType::BindRequest, enum); + PTF_ASSERT_EQUAL(bindRequestLayer->getVersion(), 3); + PTF_ASSERT_EQUAL(bindRequestLayer->getName(), ""); + PTF_ASSERT_EQUAL(bindRequestLayer->getAuthenticationType(), pcpp::LdapBindRequestLayer::AuthenticationType::Sasl, enumclass); + pcpp::LdapBindRequestLayer::SaslAuthentication expectedSaslAuthentication { + "GSS-SPNEGO", + {0x60, 0x82, 0x05, 0x1a, 0x06, 0x06, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x02, 0xa0, 0x82, 0x05, 0x0e, 0x30, 0x82, 0x05, 0x0a, 0xa0, 0x24, 0x30, 0x22, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x82, 0xf7, 0x12, 0x01, 0x02, 0x02, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x02, 0x02, 0x0a, 0xa2, 0x82, 0x04, 0xe0, 0x04, 0x82, 0x04, 0xdc, 0x60, 0x82, 0x04, 0xd8, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x12, 0x01, 0x02, 0x02, 0x01, 0x00, 0x6e, 0x82, 0x04, 0xc7, 0x30, 0x82, 0x04, 0xc3, 0xa0, 0x03, 0x02, 0x01, 0x05, 0xa1, 0x03, 0x02, 0x01, 0x0e, 0xa2, 0x07, 0x03, 0x05, 0x00, 0x20, 0x00, 0x00, 0x00, 0xa3, 0x82, 0x03, 0xe0, + 0x61, 0x82, 0x03, 0xdc, 0x30, 0x82, 0x03, 0xd8, 0xa0, 0x03, 0x02, 0x01, 0x05, 0xa1, 0x15, 0x1b, 0x13, 0x57, 0x32, 0x4b, 0x33, 0x2e, 0x56, 0x4d, 0x4e, 0x45, 0x54, 0x31, 0x2e, 0x56, 0x4d, 0x2e, 0x42, 0x41, 0x53, 0x45, 0xa2, 0x2f, + 0x30, 0x2d, 0xa0, 0x03, 0x02, 0x01, 0x02, 0xa1, 0x26, 0x30, 0x24, 0x1b, 0x04, 0x6c, 0x64, 0x61, 0x70, 0x1b, 0x1c, 0x77, 0x32, 0x6b, 0x33, 0x2d, 0x31, 0x30, 0x31, 0x2e, 0x77, 0x32, 0x6b, 0x33, 0x2e, 0x76, 0x6d, 0x6e, 0x65, 0x74, + 0x31, 0x2e, 0x76, 0x6d, 0x2e, 0x62, 0x61, 0x73, 0x65, 0xa3, 0x82, 0x03, 0x87, 0x30, 0x82, 0x03, 0x83, 0xa0, 0x03, 0x02, 0x01, 0x17, 0xa1, 0x03, 0x02, 0x01, 0x07, 0xa2, 0x82, 0x03, 0x75, 0x04, 0x82, 0x03, 0x71, 0x6a, 0x61, 0xc8, + 0x86, 0xba, 0x58, 0xd1, 0x62, 0x11, 0x3d, 0xb4, 0x26, 0x8f, 0x77, 0x43, 0xa1, 0x7e, 0xb4, 0x76, 0x18, 0x3b, 0xc0, 0xc5, 0x19, 0xad, 0xde, 0xa7, 0x65, 0x56, 0xa3, 0x70, 0x1d, 0xe3, 0x49, 0x03, 0xe6, 0xbd, 0x3f, 0x3f, 0xdc, 0xa0, + 0xb0, 0x1b, 0xbc, 0xcb, 0x9a, 0x86, 0x93, 0xb2, 0x3f, 0xa8, 0xd1, 0x98, 0x5e, 0x14, 0x92, 0x2e, 0x4c, 0xa1, 0x9b, 0x05, 0xa9, 0x07, 0x69, 0x84, 0x5a, 0x58, 0x58, 0x51, 0x5b, 0xba, 0x4a, 0xf2, 0xd7, 0xe5, 0x9b, 0xfa, 0x86, 0x34, + 0x28, 0x5a, 0x2e, 0x95, 0x4f, 0xb5, 0x18, 0x37, 0x8b, 0x8d, 0x3f, 0x27, 0x44, 0xb9, 0xbb, 0xf8, 0x84, 0x2b, 0x48, 0x07, 0x87, 0x9f, 0xf2, 0x8e, 0x55, 0xbf, 0xba, 0x49, 0x67, 0xe8, 0xc1, 0xd3, 0xb6, 0xc4, 0xe3, 0x58, 0xa5, 0x61, + 0xc5, 0x4a, 0xbb, 0xc1, 0xcb, 0x7c, 0x97, 0xb6, 0x50, 0x3f, 0xe5, 0x9b, 0x7f, 0xee, 0x64, 0x23, 0xdf, 0xfe, 0x66, 0xfe, 0x6d, 0xcb, 0x8a, 0xf0, 0x0e, 0x69, 0xc5, 0x3d, 0x6b, 0x57, 0x6f, 0x55, 0x06, 0x99, 0x04, 0x38, 0x31, 0x0f, + 0xb7, 0xdd, 0x14, 0x68, 0xa3, 0x2f, 0xd8, 0xe0, 0xde, 0xab, 0x40, 0xb1, 0x5e, 0xcf, 0xd4, 0x38, 0x56, 0x83, 0x70, 0x14, 0x0a, 0x1e, 0xda, 0xfe, 0xe7, 0x01, 0xa4, 0xa4, 0xb4, 0xe7, 0xb3, 0xaa, 0xef, 0xdc, 0x4b, 0x1a, 0xff, 0x58, + 0x68, 0xae, 0xfe, 0x5a, 0x36, 0x29, 0x4d, 0x5d, 0xd6, 0x87, 0xd5, 0xa6, 0x49, 0x31, 0x43, 0xd3, 0xad, 0xe8, 0x03, 0x1c, 0x98, 0xd2, 0x8f, 0x6c, 0x7f, 0x3d, 0xce, 0xa4, 0x14, 0x35, 0x13, 0x2f, 0x67, 0x5f, 0x26, 0x94, 0x0d, 0x1f, + 0x69, 0xe5, 0x73, 0xe5, 0xec, 0xe6, 0xed, 0x5a, 0x66, 0x11, 0x1f, 0xf9, 0xf4, 0xb0, 0x2a, 0x8d, 0xdd, 0x19, 0x08, 0x6e, 0x5b, 0x9d, 0xc0, 0xad, 0xc8, 0x6a, 0x0b, 0xc1, 0x23, 0x0f, 0x1b, 0x71, 0x5f, 0xfc, 0x40, 0x04, 0xdf, 0xc4, + 0xa7, 0xd5, 0xf7, 0x8a, 0x4d, 0xc3, 0x1a, 0xbf, 0x83, 0x0a, 0xe6, 0xe3, 0xbf, 0xd2, 0x1c, 0x87, 0xfa, 0x51, 0x96, 0x54, 0x9e, 0x13, 0x0f, 0x6a, 0x08, 0x1b, 0xaf, 0xcf, 0x41, 0x70, 0xae, 0x20, 0x1c, 0x78, 0xa3, 0x82, 0x9a, 0x01, + 0xdb, 0xa5, 0x78, 0xa2, 0xef, 0x96, 0x8f, 0x2a, 0xb6, 0x66, 0x8d, 0x81, 0x14, 0xdf, 0xcc, 0x65, 0xd7, 0x03, 0x8f, 0x55, 0x58, 0xbe, 0x7c, 0xdd, 0x92, 0x46, 0xd5, 0x22, 0x47, 0x91, 0x52, 0x60, 0xa4, 0x0e, 0x59, 0xc4, 0x8b, 0x08, + 0xa1, 0xed, 0x61, 0x42, 0x7f, 0xd3, 0x03, 0x91, 0x7c, 0x6b, 0x34, 0xb7, 0x01, 0xa4, 0xba, 0x9a, 0x38, 0x15, 0xd4, 0x82, 0x8a, 0x22, 0x8c, 0xd2, 0x09, 0xda, 0x13, 0x76, 0x26, 0xe2, 0x02, 0x9a, 0xab, 0xf6, 0xc2, 0x00, 0xbf, 0x7f, + 0xd6, 0x3c, 0xf6, 0xd4, 0x3b, 0xb6, 0x18, 0xb3, 0x1a, 0xc4, 0x8e, 0x09, 0x61, 0x35, 0x89, 0xd7, 0x4a, 0x69, 0x54, 0x2e, 0x90, 0x9c, 0xe0, 0xdc, 0x9c, 0x57, 0xc7, 0x7f, 0x7d, 0x89, 0xb9, 0x66, 0xde, 0x20, 0x00, 0x53, 0xa5, 0x8e, + 0xa5, 0x8f, 0x23, 0x74, 0x51, 0x39, 0x61, 0x63, 0x8a, 0x30, 0xca, 0x49, 0xef, 0x0e, 0xec, 0x67, 0x9d, 0x92, 0x7e, 0x38, 0x5b, 0x5d, 0xa7, 0xd4, 0xd3, 0xc1, 0xa5, 0x91, 0x69, 0xb4, 0x63, 0x0b, 0x87, 0x4a, 0x1d, 0x96, 0x9e, 0x45, + 0xd1, 0xfe, 0x37, 0x82, 0x08, 0x9f, 0x43, 0x85, 0x02, 0x49, 0x55, 0x09, 0x3b, 0x30, 0x8e, 0x19, 0x64, 0xd3, 0x07, 0x91, 0x52, 0x71, 0xaa, 0x88, 0x6c, 0x3d, 0x9b, 0x64, 0xd8, 0x46, 0xc8, 0x8c, 0xa1, 0x34, 0x1f, 0xd2, 0xf7, 0x2b, + 0x76, 0x67, 0x9d, 0x4f, 0x25, 0x8f, 0x64, 0x7b, 0xc0, 0x48, 0x20, 0xe4, 0x27, 0x76, 0xc9, 0xec, 0x0d, 0x01, 0x46, 0x46, 0x52, 0x76, 0x3a, 0x49, 0xd8, 0x22, 0xc9, 0xd2, 0x5b, 0x60, 0x39, 0x03, 0xeb, 0xd6, 0x33, 0x89, 0x52, 0x25, + 0x9b, 0x83, 0xa7, 0x40, 0xa4, 0x20, 0xd6, 0x9d, 0x23, 0xae, 0xbb, 0xdf, 0x06, 0xa9, 0x2d, 0x88, 0xa4, 0x6f, 0xfc, 0xd8, 0xd8, 0x1a, 0x47, 0xb6, 0xec, 0x99, 0xb6, 0xce, 0xa0, 0x48, 0x9c, 0xc8, 0x3e, 0xf1, 0x57, 0x57, 0xc4, 0x05, + 0x3d, 0x53, 0x84, 0x46, 0xf2, 0xe6, 0xb9, 0xeb, 0xa1, 0x2c, 0xe4, 0x96, 0x9b, 0x8d, 0x6d, 0xf9, 0xb3, 0xef, 0x57, 0x4b, 0x7d, 0x40, 0x13, 0x41, 0xc2, 0xf5, 0x55, 0xa0, 0x0f, 0x02, 0x91, 0x64, 0xe5, 0xd3, 0x87, 0x28, 0x2c, 0x0c, + 0x87, 0x91, 0xba, 0x8c, 0x69, 0x81, 0x62, 0x48, 0xe2, 0xe5, 0x44, 0xa9, 0xc1, 0x2b, 0x7a, 0xeb, 0xa6, 0x29, 0xfd, 0xee, 0xa2, 0xe1, 0x11, 0x65, 0x5e, 0x44, 0xb9, 0xc2, 0x15, 0x92, 0x4c, 0x54, 0x55, 0xea, 0xa4, 0xab, 0x32, 0xae, + 0xa1, 0xd9, 0xce, 0xf1, 0xd8, 0x6e, 0x8a, 0xcf, 0x6b, 0x0f, 0xf4, 0xdc, 0xab, 0xaf, 0x4f, 0x0e, 0x2d, 0x9a, 0xe6, 0x5c, 0x8b, 0xb1, 0x06, 0x5e, 0x04, 0x18, 0xff, 0x12, 0xd4, 0x62, 0x69, 0x30, 0x31, 0x59, 0x38, 0xbf, 0xe0, 0x0a, + 0x8d, 0x03, 0xe8, 0xe7, 0x0e, 0x9d, 0xea, 0x9d, 0xc9, 0xff, 0x74, 0x85, 0x4c, 0xbb, 0x4d, 0xbd, 0xf7, 0x00, 0xa6, 0x2e, 0x77, 0xb2, 0x6e, 0x50, 0xb1, 0x3e, 0x2d, 0x39, 0x60, 0xc9, 0x13, 0x36, 0x0c, 0x84, 0xc8, 0x7e, 0x80, 0x1e, + 0xd3, 0xdf, 0x3d, 0xb0, 0xe2, 0x76, 0x04, 0x50, 0x8c, 0xb7, 0x30, 0xc5, 0xa0, 0x52, 0xc0, 0x68, 0xab, 0xe5, 0x82, 0x6b, 0x01, 0xbe, 0x9f, 0x62, 0xe3, 0x3b, 0x9a, 0xf8, 0xed, 0xb6, 0x66, 0x7c, 0x57, 0xcb, 0x1a, 0xa8, 0x79, 0x74, + 0x3b, 0x77, 0xa7, 0x43, 0x2f, 0x75, 0xfe, 0x3a, 0xe2, 0x11, 0xf9, 0x6a, 0xf4, 0x1a, 0xde, 0xf1, 0xe1, 0xc5, 0x07, 0x25, 0x6f, 0xe5, 0xfa, 0x2b, 0xcc, 0xab, 0xe5, 0x2c, 0xf8, 0x21, 0x6d, 0x34, 0x10, 0xe6, 0x37, 0x85, 0x06, 0xd4, + 0x27, 0x34, 0x34, 0x58, 0x33, 0x2d, 0x15, 0x3a, 0x77, 0xa1, 0x62, 0xc4, 0xc5, 0xf1, 0x8d, 0x9f, 0x31, 0xb0, 0xc1, 0x42, 0x88, 0x0c, 0xad, 0x22, 0x29, 0x98, 0x17, 0x20, 0x61, 0x5a, 0xb2, 0x6b, 0x7c, 0x13, 0x44, 0x2e, 0x43, 0x17, + 0x8a, 0xad, 0xee, 0x43, 0x65, 0x10, 0xc9, 0x1b, 0xc9, 0xd5, 0xd7, 0x35, 0xeb, 0x94, 0x53, 0xcf, 0x39, 0xce, 0xf5, 0x12, 0x0e, 0x28, 0x60, 0x37, 0x75, 0xf0, 0x48, 0x3f, 0x01, 0xc3, 0xc4, 0x8b, 0x5b, 0x06, 0x0c, 0xa7, 0xf3, 0xa5, + 0x4d, 0x7c, 0x7c, 0x99, 0xa4, 0x81, 0xc9, 0x30, 0x81, 0xc6, 0xa0, 0x03, 0x02, 0x01, 0x17, 0xa2, 0x81, 0xbe, 0x04, 0x81, 0xbb, 0x03, 0xab, 0x65, 0x67, 0x60, 0xa3, 0x51, 0x2f, 0xec, 0xc7, 0x03, 0x2d, 0xa8, 0xb2, 0x01, 0x46, 0x59, + 0xf0, 0xfb, 0x34, 0xeb, 0x76, 0xb4, 0x61, 0xe4, 0x04, 0x4d, 0xa2, 0x4d, 0x16, 0xd4, 0x58, 0xe3, 0xe1, 0xc5, 0x89, 0x19, 0xc7, 0x4c, 0x4c, 0x07, 0x20, 0xaa, 0xfb, 0x87, 0xa9, 0x48, 0x15, 0x23, 0x72, 0xa2, 0x48, 0x3a, 0x4d, 0x1a, + 0xe9, 0xb9, 0x5b, 0x85, 0x8a, 0x52, 0xab, 0xaa, 0x94, 0xe7, 0xaa, 0x64, 0x1a, 0x8b, 0x99, 0x7d, 0x7e, 0x6c, 0x6e, 0x57, 0x0b, 0x59, 0x08, 0xcc, 0x54, 0x91, 0x55, 0xf5, 0xe6, 0xf1, 0x10, 0xc9, 0x8d, 0x64, 0x89, 0x78, 0x72, 0x7a, + 0xba, 0xe3, 0x92, 0x1d, 0xa5, 0x2a, 0x4c, 0x1f, 0xd7, 0x6b, 0xeb, 0x12, 0x1b, 0xf3, 0x39, 0x6b, 0xe8, 0xf9, 0x8e, 0x4a, 0xcf, 0x1e, 0xbf, 0xc3, 0xb6, 0xfb, 0x7a, 0x13, 0x54, 0xc1, 0x21, 0x87, 0x3e, 0x59, 0x18, 0x5d, 0xb9, 0x00, + 0x30, 0x08, 0x4d, 0x97, 0x86, 0x47, 0x98, 0xd7, 0x9e, 0xb9, 0xdf, 0x30, 0x75, 0x6c, 0xa1, 0xfa, 0xa7, 0xa8, 0x08, 0x80, 0xf7, 0x4f, 0x7d, 0x93, 0x64, 0x2d, 0x9c, 0xeb, 0x5e, 0x01, 0x28, 0xce, 0xd6, 0xab, 0x09, 0x6a, 0x4f, 0x01, + 0x5e, 0x5a, 0x03, 0x2b, 0x42, 0x70, 0x23, 0x1e, 0x7f, 0xf1, 0xbc, 0xd0, 0x87, 0xe8, 0xb5, 0x27, 0x02, 0x7d} + }; + PTF_ASSERT_EQUAL(bindRequestLayer->getSaslAuthentication(), expectedSaslAuthentication); + PTF_ASSERT_RAISES(bindRequestLayer->getSimpleAuthentication(), std::invalid_argument, "Authentication type is not simple"); + std::string simpleAuthentication; + PTF_ASSERT_FALSE(bindRequestLayer->tryGet(&pcpp::LdapBindRequestLayer::getSimpleAuthentication, simpleAuthentication)); + PTF_ASSERT_EQUAL(bindRequestLayer->toString(), "LDAP Layer, BindRequest, sasl"); + } + + // BindResponse with server sals credentials + { + READ_FILE_AND_CREATE_PACKET(1, "PacketExamples/ldap_bind_response1.dat"); + pcpp::Packet bindResponsePacket(&rawPacket1); + + auto bindResponseLayer = bindResponsePacket.getLayerOfType(); + PTF_ASSERT_NOT_NULL(bindResponseLayer); + PTF_ASSERT_EQUAL(bindResponseLayer->getMessageID(), 215); + PTF_ASSERT_EQUAL(bindResponseLayer->getLdapOperationType(), pcpp::LdapOperationType::BindResponse, enum); + PTF_ASSERT_EQUAL(bindResponseLayer->getResultCode(), pcpp::LdapResultCode::Success, enum); + PTF_ASSERT_EQUAL(bindResponseLayer->getMatchedDN(), ""); + PTF_ASSERT_EQUAL(bindResponseLayer->getDiagnosticMessage(), ""); + PTF_ASSERT_VECTORS_EQUAL(bindResponseLayer->getReferral(), std::vector()); + std::vector expectedServerSaslCredentials = { + 0xa1, 0x81, 0xa1, 0x30, 0x81, 0x9e, 0xa0, 0x03, 0x0a, 0x01, 0x00, 0xa1, 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x82, 0xf7, 0x12, 0x01, 0x02, 0x02, 0xa2, 0x81, 0x89, 0x04, 0x81, 0x86, 0x60, 0x81, 0x83, 0x06, 0x09, 0x2a, 0x86, 0x48, + 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02, 0x02, 0x00, 0x6f, 0x74, 0x30, 0x72, 0xa0, 0x03, 0x02, 0x01, 0x05, 0xa1, 0x03, 0x02, 0x01, 0x0f, 0xa2, 0x66, 0x30, 0x64, 0xa0, 0x03, 0x02, 0x01, 0x17, 0xa2, 0x5d, 0x04, 0x5b, 0x4a, 0x9f, 0x10, + 0xab, 0x89, 0x96, 0xfa, 0x43, 0xf2, 0xfb, 0x40, 0x92, 0xa7, 0x6c, 0xc3, 0xfa, 0x6c, 0x1f, 0x00, 0x11, 0x67, 0xfa, 0xc9, 0x04, 0xda, 0xb0, 0x67, 0xf5, 0xf2, 0xda, 0x59, 0xa7, 0x54, 0x90, 0x57, 0xbd, 0x3e, 0xb4, 0x6c, 0xb4, 0x67, + 0xfd, 0x3b, 0x01, 0xd7, 0x3f, 0x50, 0x51, 0xaa, 0x63, 0x2e, 0xd8, 0xd6, 0xa6, 0xe5, 0x81, 0xbb, 0xab, 0x17, 0x80, 0xfa, 0xab, 0xac, 0x51, 0x52, 0x84, 0x13, 0x9c, 0xfb, 0x44, 0xc2, 0x04, 0xae, 0x1e, 0xc2, 0x5a, 0x2d, 0x58, 0x90, + 0x9d, 0x22, 0xff, 0x52, 0x34, 0x9e, 0x6d, 0x2e, 0x4d, 0x83, 0x5b, 0x98}; + PTF_ASSERT_VECTORS_EQUAL(bindResponseLayer->getServerSaslCredentials(), expectedServerSaslCredentials); + } + + // BindResponse without server sals credentials + { + READ_FILE_AND_CREATE_PACKET(1, "PacketExamples/ldap_bind_response2.dat"); + pcpp::Packet bindResponsePacket(&rawPacket1); + + auto bindResponseLayer = bindResponsePacket.getLayerOfType(); + PTF_ASSERT_NOT_NULL(bindResponseLayer); + PTF_ASSERT_EQUAL(bindResponseLayer->getMessageID(), 2); + PTF_ASSERT_EQUAL(bindResponseLayer->getLdapOperationType(), pcpp::LdapOperationType::BindResponse, enum); + PTF_ASSERT_EQUAL(bindResponseLayer->getResultCode(), pcpp::LdapResultCode::Success, enum); + PTF_ASSERT_EQUAL(bindResponseLayer->getMatchedDN(), ""); + PTF_ASSERT_EQUAL(bindResponseLayer->getDiagnosticMessage(), ""); + PTF_ASSERT_VECTORS_EQUAL(bindResponseLayer->getReferral(), std::vector()); + PTF_ASSERT_VECTORS_EQUAL(bindResponseLayer->getServerSaslCredentials(), std::vector()); + } + + // UnbindRequest + { + READ_FILE_AND_CREATE_PACKET(1, "PacketExamples/ldap_unbind_request.dat"); + pcpp::Packet unbindRequestPacket(&rawPacket1); + + auto unbindRequestLayer = unbindRequestPacket.getLayerOfType(); + PTF_ASSERT_NOT_NULL(unbindRequestLayer); + PTF_ASSERT_EQUAL(unbindRequestLayer->getMessageID(), 3); + PTF_ASSERT_EQUAL(unbindRequestLayer->getLdapOperationType(), pcpp::LdapOperationType::UnbindRequest, enum); + PTF_ASSERT_EQUAL(unbindRequestLayer->toString(), "LDAP Layer, UnbindRequest"); + } + // SearchRequest { READ_FILE_AND_CREATE_PACKET(1, "PacketExamples/ldap_search_request2.dat"); @@ -327,6 +453,137 @@ PTF_TEST_CASE(LdapCreationTest) PTF_ASSERT_BUF_COMPARE(ldapLayer.getData(), expectedLdapLayer->getData(), expectedLdapLayer->getDataLen()); } + // BindRequest with simple authentication + { + READ_FILE_AND_CREATE_PACKET(1, "PacketExamples/ldap_bind_request1.dat"); + pcpp::Packet bindRequestPacket(&rawPacket1); + + pcpp::LdapBindRequestLayer bindRequestLayer(2, 3, "cn=Administrator,cn=Users,dc=cloudshark-a,dc=example,dc=com", + "cloudshark123!", {{"1.3.6.1.4.1.42.2.27.8.5.1"}}); + + auto expectedBindRequestLayer = bindRequestPacket.getLayerOfType(); + PTF_ASSERT_NOT_NULL(expectedBindRequestLayer); + + PTF_ASSERT_BUF_COMPARE(bindRequestLayer.getData(), expectedBindRequestLayer->getData(), + expectedBindRequestLayer->getDataLen()); + } + + // BindRequest with sasl authentication + { + READ_FILE_AND_CREATE_PACKET(1, "PacketExamples/ldap_bind_request2.dat"); + pcpp::Packet bindRequestPacket(&rawPacket1); + + pcpp::LdapBindRequestLayer::SaslAuthentication saslAuthentication { + "GSS-SPNEGO", + {0x60, 0x82, 0x05, 0x1a, 0x06, 0x06, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x02, 0xa0, 0x82, 0x05, 0x0e, 0x30, 0x82, 0x05, 0x0a, 0xa0, 0x24, 0x30, 0x22, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x82, 0xf7, 0x12, 0x01, 0x02, 0x02, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x02, 0x02, 0x0a, 0xa2, 0x82, 0x04, 0xe0, 0x04, 0x82, 0x04, 0xdc, 0x60, 0x82, 0x04, 0xd8, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x12, 0x01, 0x02, 0x02, 0x01, 0x00, 0x6e, 0x82, 0x04, 0xc7, 0x30, 0x82, 0x04, 0xc3, 0xa0, 0x03, 0x02, 0x01, 0x05, 0xa1, 0x03, 0x02, 0x01, 0x0e, 0xa2, 0x07, 0x03, 0x05, 0x00, 0x20, 0x00, 0x00, 0x00, 0xa3, 0x82, 0x03, 0xe0, + 0x61, 0x82, 0x03, 0xdc, 0x30, 0x82, 0x03, 0xd8, 0xa0, 0x03, 0x02, 0x01, 0x05, 0xa1, 0x15, 0x1b, 0x13, 0x57, 0x32, 0x4b, 0x33, 0x2e, 0x56, 0x4d, 0x4e, 0x45, 0x54, 0x31, 0x2e, 0x56, 0x4d, 0x2e, 0x42, 0x41, 0x53, 0x45, 0xa2, 0x2f, + 0x30, 0x2d, 0xa0, 0x03, 0x02, 0x01, 0x02, 0xa1, 0x26, 0x30, 0x24, 0x1b, 0x04, 0x6c, 0x64, 0x61, 0x70, 0x1b, 0x1c, 0x77, 0x32, 0x6b, 0x33, 0x2d, 0x31, 0x30, 0x31, 0x2e, 0x77, 0x32, 0x6b, 0x33, 0x2e, 0x76, 0x6d, 0x6e, 0x65, 0x74, + 0x31, 0x2e, 0x76, 0x6d, 0x2e, 0x62, 0x61, 0x73, 0x65, 0xa3, 0x82, 0x03, 0x87, 0x30, 0x82, 0x03, 0x83, 0xa0, 0x03, 0x02, 0x01, 0x17, 0xa1, 0x03, 0x02, 0x01, 0x07, 0xa2, 0x82, 0x03, 0x75, 0x04, 0x82, 0x03, 0x71, 0x6a, 0x61, 0xc8, + 0x86, 0xba, 0x58, 0xd1, 0x62, 0x11, 0x3d, 0xb4, 0x26, 0x8f, 0x77, 0x43, 0xa1, 0x7e, 0xb4, 0x76, 0x18, 0x3b, 0xc0, 0xc5, 0x19, 0xad, 0xde, 0xa7, 0x65, 0x56, 0xa3, 0x70, 0x1d, 0xe3, 0x49, 0x03, 0xe6, 0xbd, 0x3f, 0x3f, 0xdc, 0xa0, + 0xb0, 0x1b, 0xbc, 0xcb, 0x9a, 0x86, 0x93, 0xb2, 0x3f, 0xa8, 0xd1, 0x98, 0x5e, 0x14, 0x92, 0x2e, 0x4c, 0xa1, 0x9b, 0x05, 0xa9, 0x07, 0x69, 0x84, 0x5a, 0x58, 0x58, 0x51, 0x5b, 0xba, 0x4a, 0xf2, 0xd7, 0xe5, 0x9b, 0xfa, 0x86, 0x34, + 0x28, 0x5a, 0x2e, 0x95, 0x4f, 0xb5, 0x18, 0x37, 0x8b, 0x8d, 0x3f, 0x27, 0x44, 0xb9, 0xbb, 0xf8, 0x84, 0x2b, 0x48, 0x07, 0x87, 0x9f, 0xf2, 0x8e, 0x55, 0xbf, 0xba, 0x49, 0x67, 0xe8, 0xc1, 0xd3, 0xb6, 0xc4, 0xe3, 0x58, 0xa5, 0x61, + 0xc5, 0x4a, 0xbb, 0xc1, 0xcb, 0x7c, 0x97, 0xb6, 0x50, 0x3f, 0xe5, 0x9b, 0x7f, 0xee, 0x64, 0x23, 0xdf, 0xfe, 0x66, 0xfe, 0x6d, 0xcb, 0x8a, 0xf0, 0x0e, 0x69, 0xc5, 0x3d, 0x6b, 0x57, 0x6f, 0x55, 0x06, 0x99, 0x04, 0x38, 0x31, 0x0f, + 0xb7, 0xdd, 0x14, 0x68, 0xa3, 0x2f, 0xd8, 0xe0, 0xde, 0xab, 0x40, 0xb1, 0x5e, 0xcf, 0xd4, 0x38, 0x56, 0x83, 0x70, 0x14, 0x0a, 0x1e, 0xda, 0xfe, 0xe7, 0x01, 0xa4, 0xa4, 0xb4, 0xe7, 0xb3, 0xaa, 0xef, 0xdc, 0x4b, 0x1a, 0xff, 0x58, + 0x68, 0xae, 0xfe, 0x5a, 0x36, 0x29, 0x4d, 0x5d, 0xd6, 0x87, 0xd5, 0xa6, 0x49, 0x31, 0x43, 0xd3, 0xad, 0xe8, 0x03, 0x1c, 0x98, 0xd2, 0x8f, 0x6c, 0x7f, 0x3d, 0xce, 0xa4, 0x14, 0x35, 0x13, 0x2f, 0x67, 0x5f, 0x26, 0x94, 0x0d, 0x1f, + 0x69, 0xe5, 0x73, 0xe5, 0xec, 0xe6, 0xed, 0x5a, 0x66, 0x11, 0x1f, 0xf9, 0xf4, 0xb0, 0x2a, 0x8d, 0xdd, 0x19, 0x08, 0x6e, 0x5b, 0x9d, 0xc0, 0xad, 0xc8, 0x6a, 0x0b, 0xc1, 0x23, 0x0f, 0x1b, 0x71, 0x5f, 0xfc, 0x40, 0x04, 0xdf, 0xc4, + 0xa7, 0xd5, 0xf7, 0x8a, 0x4d, 0xc3, 0x1a, 0xbf, 0x83, 0x0a, 0xe6, 0xe3, 0xbf, 0xd2, 0x1c, 0x87, 0xfa, 0x51, 0x96, 0x54, 0x9e, 0x13, 0x0f, 0x6a, 0x08, 0x1b, 0xaf, 0xcf, 0x41, 0x70, 0xae, 0x20, 0x1c, 0x78, 0xa3, 0x82, 0x9a, 0x01, + 0xdb, 0xa5, 0x78, 0xa2, 0xef, 0x96, 0x8f, 0x2a, 0xb6, 0x66, 0x8d, 0x81, 0x14, 0xdf, 0xcc, 0x65, 0xd7, 0x03, 0x8f, 0x55, 0x58, 0xbe, 0x7c, 0xdd, 0x92, 0x46, 0xd5, 0x22, 0x47, 0x91, 0x52, 0x60, 0xa4, 0x0e, 0x59, 0xc4, 0x8b, 0x08, + 0xa1, 0xed, 0x61, 0x42, 0x7f, 0xd3, 0x03, 0x91, 0x7c, 0x6b, 0x34, 0xb7, 0x01, 0xa4, 0xba, 0x9a, 0x38, 0x15, 0xd4, 0x82, 0x8a, 0x22, 0x8c, 0xd2, 0x09, 0xda, 0x13, 0x76, 0x26, 0xe2, 0x02, 0x9a, 0xab, 0xf6, 0xc2, 0x00, 0xbf, 0x7f, + 0xd6, 0x3c, 0xf6, 0xd4, 0x3b, 0xb6, 0x18, 0xb3, 0x1a, 0xc4, 0x8e, 0x09, 0x61, 0x35, 0x89, 0xd7, 0x4a, 0x69, 0x54, 0x2e, 0x90, 0x9c, 0xe0, 0xdc, 0x9c, 0x57, 0xc7, 0x7f, 0x7d, 0x89, 0xb9, 0x66, 0xde, 0x20, 0x00, 0x53, 0xa5, 0x8e, + 0xa5, 0x8f, 0x23, 0x74, 0x51, 0x39, 0x61, 0x63, 0x8a, 0x30, 0xca, 0x49, 0xef, 0x0e, 0xec, 0x67, 0x9d, 0x92, 0x7e, 0x38, 0x5b, 0x5d, 0xa7, 0xd4, 0xd3, 0xc1, 0xa5, 0x91, 0x69, 0xb4, 0x63, 0x0b, 0x87, 0x4a, 0x1d, 0x96, 0x9e, 0x45, + 0xd1, 0xfe, 0x37, 0x82, 0x08, 0x9f, 0x43, 0x85, 0x02, 0x49, 0x55, 0x09, 0x3b, 0x30, 0x8e, 0x19, 0x64, 0xd3, 0x07, 0x91, 0x52, 0x71, 0xaa, 0x88, 0x6c, 0x3d, 0x9b, 0x64, 0xd8, 0x46, 0xc8, 0x8c, 0xa1, 0x34, 0x1f, 0xd2, 0xf7, 0x2b, + 0x76, 0x67, 0x9d, 0x4f, 0x25, 0x8f, 0x64, 0x7b, 0xc0, 0x48, 0x20, 0xe4, 0x27, 0x76, 0xc9, 0xec, 0x0d, 0x01, 0x46, 0x46, 0x52, 0x76, 0x3a, 0x49, 0xd8, 0x22, 0xc9, 0xd2, 0x5b, 0x60, 0x39, 0x03, 0xeb, 0xd6, 0x33, 0x89, 0x52, 0x25, + 0x9b, 0x83, 0xa7, 0x40, 0xa4, 0x20, 0xd6, 0x9d, 0x23, 0xae, 0xbb, 0xdf, 0x06, 0xa9, 0x2d, 0x88, 0xa4, 0x6f, 0xfc, 0xd8, 0xd8, 0x1a, 0x47, 0xb6, 0xec, 0x99, 0xb6, 0xce, 0xa0, 0x48, 0x9c, 0xc8, 0x3e, 0xf1, 0x57, 0x57, 0xc4, 0x05, + 0x3d, 0x53, 0x84, 0x46, 0xf2, 0xe6, 0xb9, 0xeb, 0xa1, 0x2c, 0xe4, 0x96, 0x9b, 0x8d, 0x6d, 0xf9, 0xb3, 0xef, 0x57, 0x4b, 0x7d, 0x40, 0x13, 0x41, 0xc2, 0xf5, 0x55, 0xa0, 0x0f, 0x02, 0x91, 0x64, 0xe5, 0xd3, 0x87, 0x28, 0x2c, 0x0c, + 0x87, 0x91, 0xba, 0x8c, 0x69, 0x81, 0x62, 0x48, 0xe2, 0xe5, 0x44, 0xa9, 0xc1, 0x2b, 0x7a, 0xeb, 0xa6, 0x29, 0xfd, 0xee, 0xa2, 0xe1, 0x11, 0x65, 0x5e, 0x44, 0xb9, 0xc2, 0x15, 0x92, 0x4c, 0x54, 0x55, 0xea, 0xa4, 0xab, 0x32, 0xae, + 0xa1, 0xd9, 0xce, 0xf1, 0xd8, 0x6e, 0x8a, 0xcf, 0x6b, 0x0f, 0xf4, 0xdc, 0xab, 0xaf, 0x4f, 0x0e, 0x2d, 0x9a, 0xe6, 0x5c, 0x8b, 0xb1, 0x06, 0x5e, 0x04, 0x18, 0xff, 0x12, 0xd4, 0x62, 0x69, 0x30, 0x31, 0x59, 0x38, 0xbf, 0xe0, 0x0a, + 0x8d, 0x03, 0xe8, 0xe7, 0x0e, 0x9d, 0xea, 0x9d, 0xc9, 0xff, 0x74, 0x85, 0x4c, 0xbb, 0x4d, 0xbd, 0xf7, 0x00, 0xa6, 0x2e, 0x77, 0xb2, 0x6e, 0x50, 0xb1, 0x3e, 0x2d, 0x39, 0x60, 0xc9, 0x13, 0x36, 0x0c, 0x84, 0xc8, 0x7e, 0x80, 0x1e, + 0xd3, 0xdf, 0x3d, 0xb0, 0xe2, 0x76, 0x04, 0x50, 0x8c, 0xb7, 0x30, 0xc5, 0xa0, 0x52, 0xc0, 0x68, 0xab, 0xe5, 0x82, 0x6b, 0x01, 0xbe, 0x9f, 0x62, 0xe3, 0x3b, 0x9a, 0xf8, 0xed, 0xb6, 0x66, 0x7c, 0x57, 0xcb, 0x1a, 0xa8, 0x79, 0x74, + 0x3b, 0x77, 0xa7, 0x43, 0x2f, 0x75, 0xfe, 0x3a, 0xe2, 0x11, 0xf9, 0x6a, 0xf4, 0x1a, 0xde, 0xf1, 0xe1, 0xc5, 0x07, 0x25, 0x6f, 0xe5, 0xfa, 0x2b, 0xcc, 0xab, 0xe5, 0x2c, 0xf8, 0x21, 0x6d, 0x34, 0x10, 0xe6, 0x37, 0x85, 0x06, 0xd4, + 0x27, 0x34, 0x34, 0x58, 0x33, 0x2d, 0x15, 0x3a, 0x77, 0xa1, 0x62, 0xc4, 0xc5, 0xf1, 0x8d, 0x9f, 0x31, 0xb0, 0xc1, 0x42, 0x88, 0x0c, 0xad, 0x22, 0x29, 0x98, 0x17, 0x20, 0x61, 0x5a, 0xb2, 0x6b, 0x7c, 0x13, 0x44, 0x2e, 0x43, 0x17, + 0x8a, 0xad, 0xee, 0x43, 0x65, 0x10, 0xc9, 0x1b, 0xc9, 0xd5, 0xd7, 0x35, 0xeb, 0x94, 0x53, 0xcf, 0x39, 0xce, 0xf5, 0x12, 0x0e, 0x28, 0x60, 0x37, 0x75, 0xf0, 0x48, 0x3f, 0x01, 0xc3, 0xc4, 0x8b, 0x5b, 0x06, 0x0c, 0xa7, 0xf3, 0xa5, + 0x4d, 0x7c, 0x7c, 0x99, 0xa4, 0x81, 0xc9, 0x30, 0x81, 0xc6, 0xa0, 0x03, 0x02, 0x01, 0x17, 0xa2, 0x81, 0xbe, 0x04, 0x81, 0xbb, 0x03, 0xab, 0x65, 0x67, 0x60, 0xa3, 0x51, 0x2f, 0xec, 0xc7, 0x03, 0x2d, 0xa8, 0xb2, 0x01, 0x46, 0x59, + 0xf0, 0xfb, 0x34, 0xeb, 0x76, 0xb4, 0x61, 0xe4, 0x04, 0x4d, 0xa2, 0x4d, 0x16, 0xd4, 0x58, 0xe3, 0xe1, 0xc5, 0x89, 0x19, 0xc7, 0x4c, 0x4c, 0x07, 0x20, 0xaa, 0xfb, 0x87, 0xa9, 0x48, 0x15, 0x23, 0x72, 0xa2, 0x48, 0x3a, 0x4d, 0x1a, + 0xe9, 0xb9, 0x5b, 0x85, 0x8a, 0x52, 0xab, 0xaa, 0x94, 0xe7, 0xaa, 0x64, 0x1a, 0x8b, 0x99, 0x7d, 0x7e, 0x6c, 0x6e, 0x57, 0x0b, 0x59, 0x08, 0xcc, 0x54, 0x91, 0x55, 0xf5, 0xe6, 0xf1, 0x10, 0xc9, 0x8d, 0x64, 0x89, 0x78, 0x72, 0x7a, + 0xba, 0xe3, 0x92, 0x1d, 0xa5, 0x2a, 0x4c, 0x1f, 0xd7, 0x6b, 0xeb, 0x12, 0x1b, 0xf3, 0x39, 0x6b, 0xe8, 0xf9, 0x8e, 0x4a, 0xcf, 0x1e, 0xbf, 0xc3, 0xb6, 0xfb, 0x7a, 0x13, 0x54, 0xc1, 0x21, 0x87, 0x3e, 0x59, 0x18, 0x5d, 0xb9, 0x00, + 0x30, 0x08, 0x4d, 0x97, 0x86, 0x47, 0x98, 0xd7, 0x9e, 0xb9, 0xdf, 0x30, 0x75, 0x6c, 0xa1, 0xfa, 0xa7, 0xa8, 0x08, 0x80, 0xf7, 0x4f, 0x7d, 0x93, 0x64, 0x2d, 0x9c, 0xeb, 0x5e, 0x01, 0x28, 0xce, 0xd6, 0xab, 0x09, 0x6a, 0x4f, 0x01, + 0x5e, 0x5a, 0x03, 0x2b, 0x42, 0x70, 0x23, 0x1e, 0x7f, 0xf1, 0xbc, 0xd0, 0x87, 0xe8, 0xb5, 0x27, 0x02, 0x7d} + }; + pcpp::LdapBindRequestLayer bindRequestLayer(2, 3, "", saslAuthentication); + + auto expectedBindRequestLayer = bindRequestPacket.getLayerOfType(); + PTF_ASSERT_NOT_NULL(expectedBindRequestLayer); + + PTF_ASSERT_EQUAL(bindRequestLayer.getLdapOperationAsn1Record()->getSubRecords().size(), expectedBindRequestLayer->getLdapOperationAsn1Record()->getSubRecords().size()); + PTF_ASSERT_TRUE(std::equal(bindRequestLayer.getLdapOperationAsn1Record()->getSubRecords().begin(), + bindRequestLayer.getLdapOperationAsn1Record()->getSubRecords().end(), + expectedBindRequestLayer->getLdapOperationAsn1Record()->getSubRecords().begin(), + [](pcpp::Asn1Record* elem1, pcpp::Asn1Record* elem2) { return elem1->encode() == elem2->encode();})); + } + + // BindResponse with server sasl credentials + { + READ_FILE_AND_CREATE_PACKET(1, "PacketExamples/ldap_bind_response1.dat"); + pcpp::Packet bindResponsePacket(&rawPacket1); + + std::vector serverSaslCredentials = { + 0xa1, 0x81, 0xa1, 0x30, 0x81, 0x9e, 0xa0, 0x03, 0x0a, 0x01, 0x00, 0xa1, 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x82, 0xf7, 0x12, 0x01, 0x02, 0x02, 0xa2, 0x81, 0x89, 0x04, 0x81, 0x86, 0x60, 0x81, 0x83, 0x06, 0x09, 0x2a, 0x86, 0x48, + 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02, 0x02, 0x00, 0x6f, 0x74, 0x30, 0x72, 0xa0, 0x03, 0x02, 0x01, 0x05, 0xa1, 0x03, 0x02, 0x01, 0x0f, 0xa2, 0x66, 0x30, 0x64, 0xa0, 0x03, 0x02, 0x01, 0x17, 0xa2, 0x5d, 0x04, 0x5b, 0x4a, 0x9f, 0x10, + 0xab, 0x89, 0x96, 0xfa, 0x43, 0xf2, 0xfb, 0x40, 0x92, 0xa7, 0x6c, 0xc3, 0xfa, 0x6c, 0x1f, 0x00, 0x11, 0x67, 0xfa, 0xc9, 0x04, 0xda, 0xb0, 0x67, 0xf5, 0xf2, 0xda, 0x59, 0xa7, 0x54, 0x90, 0x57, 0xbd, 0x3e, 0xb4, 0x6c, 0xb4, 0x67, + 0xfd, 0x3b, 0x01, 0xd7, 0x3f, 0x50, 0x51, 0xaa, 0x63, 0x2e, 0xd8, 0xd6, 0xa6, 0xe5, 0x81, 0xbb, 0xab, 0x17, 0x80, 0xfa, 0xab, 0xac, 0x51, 0x52, 0x84, 0x13, 0x9c, 0xfb, 0x44, 0xc2, 0x04, 0xae, 0x1e, 0xc2, 0x5a, 0x2d, 0x58, 0x90, + 0x9d, 0x22, 0xff, 0x52, 0x34, 0x9e, 0x6d, 0x2e, 0x4d, 0x83, 0x5b, 0x98}; + + pcpp::LdapBindResponseLayer bindResponseLayer(215, pcpp::LdapResultCode::Success, "", "", {}, serverSaslCredentials); + + auto expectedBindResponseLayer = bindResponsePacket.getLayerOfType(); + PTF_ASSERT_NOT_NULL(expectedBindResponseLayer); + + PTF_ASSERT_EQUAL(bindResponseLayer.getLdapOperationAsn1Record()->getSubRecords().size(), expectedBindResponseLayer->getLdapOperationAsn1Record()->getSubRecords().size()); + + for (int i = 0; i < 3; i++) + { + PTF_ASSERT_EQUAL(bindResponseLayer.getLdapOperationAsn1Record()->getSubRecords().at(i)->toString(), + expectedBindResponseLayer->getLdapOperationAsn1Record()->getSubRecords().at(i)->toString()); + } + + auto actualServerSaslCredentialsRecord = bindResponseLayer.getLdapOperationAsn1Record()->getSubRecords().at(3)->castAs(); + auto expectedServerSaslCredentialsRecord = expectedBindResponseLayer->getLdapOperationAsn1Record()->getSubRecords().at(3)->castAs(); + PTF_ASSERT_BUF_COMPARE(actualServerSaslCredentialsRecord->getValue(), expectedServerSaslCredentialsRecord->getValue(), expectedServerSaslCredentialsRecord->getValueLength()) + } + + // BindResponse without server sasl credentials + { + READ_FILE_AND_CREATE_PACKET(1, "PacketExamples/ldap_bind_response2.dat"); + pcpp::Packet bindResponsePacket(&rawPacket1); + + pcpp::LdapBindResponseLayer bindResponseLayer(2, pcpp::LdapResultCode::Success, "", ""); + + auto expectedBindResponseLayer = bindResponsePacket.getLayerOfType(); + PTF_ASSERT_NOT_NULL(expectedBindResponseLayer); + + PTF_ASSERT_EQUAL(bindResponseLayer.getLdapOperationAsn1Record()->getSubRecords().size(), expectedBindResponseLayer->getLdapOperationAsn1Record()->getSubRecords().size()); + PTF_ASSERT_TRUE(std::equal(bindResponseLayer.getLdapOperationAsn1Record()->getSubRecords().begin(), + bindResponseLayer.getLdapOperationAsn1Record()->getSubRecords().end(), + expectedBindResponseLayer->getLdapOperationAsn1Record()->getSubRecords().begin(), + [](pcpp::Asn1Record* elem1, pcpp::Asn1Record* elem2) { return elem1->encode() == elem2->encode();})); + } + + // UnbindRequest + { + READ_FILE_AND_CREATE_PACKET(1, "PacketExamples/ldap_unbind_request.dat"); + pcpp::Packet unbindRequestPacket(&rawPacket1); + + pcpp::LdapUnbindRequestLayer unbindRequestLayer(3); + + auto expectedUnbindRequestLayer = unbindRequestPacket.getLayerOfType(); + PTF_ASSERT_NOT_NULL(expectedUnbindRequestLayer); + + PTF_ASSERT_BUF_COMPARE(unbindRequestLayer.getData(), expectedUnbindRequestLayer->getData(), + expectedUnbindRequestLayer->getDataLen()); + } + // SearchRequest { READ_FILE_AND_CREATE_PACKET(1, "PacketExamples/ldap_search_request2.dat");