// Copyright 2017 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef NET_NTLM_NTLM_CONSTANTS_H_ #define NET_NTLM_NTLM_CONSTANTS_H_ #include #include #include #include "net/base/net_export.h" namespace net::ntlm { // A security buffer is a structure within an NTLM message that indicates // the offset from the beginning of the message and the length of a payload // that occurs later in the message. Within the raw message there is also // an additional field, however the field is always written with the same // value as length, and readers must always ignore it. struct SecurityBuffer { SecurityBuffer(uint32_t offset, uint16_t length) : offset(offset), length(length) {} SecurityBuffer() : SecurityBuffer(0, 0) {} uint32_t offset; uint16_t length; }; struct NtlmFeatures { explicit NtlmFeatures(bool enable_NTLMv2) : enable_NTLMv2(enable_NTLMv2) {} // Whether the use NTLMv2. bool enable_NTLMv2 = true; // Enables Message Integrity Check (MIC). This flag is ignored if // enable_NTLMv2 is false. bool enable_MIC = true; // Enables Extended Protection for Authentication (EPA). This flag is // ignored if enable_NTLMv2 is false. bool enable_EPA = true; }; // There are 3 types of messages in NTLM. The message type is a field in // every NTLM message header. See [MS-NLMP] Section 2.2. enum class MessageType : uint32_t { kNegotiate = 0x01, kChallenge = 0x02, kAuthenticate = 0x03, }; // Defined in [MS-NLMP] Section 2.2.2.5 // Only the used subset is defined. enum class NegotiateFlags : uint32_t { kNone = 0, kUnicode = 0x01, kOem = 0x02, kRequestTarget = 0x04, kNtlm = 0x200, kAlwaysSign = 0x8000, kExtendedSessionSecurity = 0x80000, kTargetInfo = 0x800000, }; constexpr NegotiateFlags operator|(NegotiateFlags lhs, NegotiateFlags rhs) { using TFlagsInt = std::underlying_type::type; return static_cast(static_cast(lhs) | static_cast(rhs)); } constexpr NegotiateFlags operator&(NegotiateFlags lhs, NegotiateFlags rhs) { using TFlagsInt = std::underlying_type::type; return static_cast(static_cast(lhs) & static_cast(rhs)); } // Identifies the payload type in an AV Pair. See [MS-NLMP] 2.2.2.1 enum class TargetInfoAvId : uint16_t { kEol = 0x0000, kServerName = 0x00001, kDomainName = 0x00002, kFlags = 0x0006, kTimestamp = 0x0007, kTargetName = 0x0009, kChannelBindings = 0x000A, }; // Flags used in an TargetInfoAvId::kFlags AV Pair. See [MS-NLMP] 2.2.2.1 enum class TargetInfoAvFlags : uint32_t { kNone = 0, kMicPresent = 0x00000002, }; using TAvFlagsInt = std::underlying_type::type; constexpr TargetInfoAvFlags operator|(TargetInfoAvFlags lhs, TargetInfoAvFlags rhs) { return static_cast(static_cast(lhs) | static_cast(rhs)); } constexpr TargetInfoAvFlags operator&(TargetInfoAvFlags lhs, TargetInfoAvFlags rhs) { return static_cast(static_cast(lhs) & static_cast(rhs)); } // An AV Pair is a structure that appears inside the target info field. It // consists of an |avid| to identify the data type and an |avlen| specifying // the size of the payload. Following that is |avlen| bytes of inline payload. // AV Pairs are concatenated together and a special terminator with |avid| // equal to |kEol| and |avlen| equal to zero signals that no further pairs // follow. See [MS-NLMP] 2.2.2.1 // // AV Pairs from the Challenge message are read from the challenge message // and a potentially modified version is written into the authenticate // message. In some cases the existing AV Pair is modified, eg. flags. In // some cases new AV Pairs are add, eg. channel bindings and spn. // // For simplicity of processing two special fields |flags|, and |timestamp| // are populated during the initial parsing phase for AVIDs |kFlags| and // |kTimestamp| respectively. This avoids subsequent code having to // manipulate the payload value through the buffer directly. For all // other AvPairs the value of these 2 fields is undefined and the payload // is in the |buffer| field. For these fields the payload is copied verbatim // and it's content is not read or validated in any way. struct NET_EXPORT_PRIVATE AvPair { AvPair(); AvPair(TargetInfoAvId avid, uint16_t avlen); AvPair(TargetInfoAvId avid, std::vector buffer); AvPair(const AvPair& other); AvPair(AvPair&& other); ~AvPair(); AvPair& operator=(const AvPair& other); AvPair& operator=(AvPair&& other); std::vector buffer; uint64_t timestamp; TargetInfoAvFlags flags; TargetInfoAvId avid; uint16_t avlen; }; static constexpr uint8_t kSignature[] = "NTLMSSP"; static constexpr size_t kSignatureLen = std::size(kSignature); static constexpr uint16_t kProofInputVersionV2 = 0x0101; static constexpr size_t kSecurityBufferLen = (2 * sizeof(uint16_t)) + sizeof(uint32_t); static constexpr size_t kNegotiateMessageLen = 32; static constexpr size_t kMinChallengeHeaderLen = 32; static constexpr size_t kChallengeHeaderLen = 48; static constexpr size_t kResponseLenV1 = 24; static constexpr size_t kChallengeLen = 8; static constexpr size_t kVersionFieldLen = 8; static constexpr size_t kNtlmHashLen = 16; static constexpr size_t kNtlmProofLenV2 = kNtlmHashLen; static constexpr size_t kSessionKeyLenV2 = kNtlmHashLen; static constexpr size_t kMicLenV2 = kNtlmHashLen; static constexpr size_t kChannelBindingsHashLen = kNtlmHashLen; static constexpr size_t kEpaUnhashedStructHeaderLen = 20; static constexpr size_t kProofInputLenV2 = 28; static constexpr size_t kAvPairHeaderLen = 2 * sizeof(uint16_t); static constexpr size_t kNtlmResponseHeaderLenV2 = kNtlmProofLenV2 + kProofInputLenV2; static constexpr size_t kAuthenticateHeaderLenV1 = 64; static constexpr size_t kMicOffsetV2 = 72; static constexpr size_t kAuthenticateHeaderLenV2 = 88; static constexpr size_t kMaxFqdnLen = 255; static constexpr size_t kMaxUsernameLen = 104; static constexpr size_t kMaxPasswordLen = 256; static constexpr NegotiateFlags kNegotiateMessageFlags = NegotiateFlags::kUnicode | NegotiateFlags::kOem | NegotiateFlags::kRequestTarget | NegotiateFlags::kNtlm | NegotiateFlags::kAlwaysSign | NegotiateFlags::kExtendedSessionSecurity; } // namespace net::ntlm #endif // NET_NTLM_NTLM_CONSTANTS_H_