• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // Based on [MS-NLMP]: NT LAN Manager (NTLM) Authentication Protocol
6 // Specification version 28.0 [1], an unofficial NTLM reference [2], and a
7 // blog post describing Extended Protection for Authentication [3].
8 //
9 // [1] https://msdn.microsoft.com/en-us/library/cc236621.aspx
10 // [2] http://davenport.sourceforge.net/ntlm.html
11 // [3]
12 // https://blogs.msdn.microsoft.com/openspecification/2013/03/26/ntlm-and-channel-binding-hash-aka-extended-protection-for-authentication/
13 
14 #ifndef NET_NTLM_NTLM_CLIENT_H_
15 #define NET_NTLM_NTLM_CLIENT_H_
16 
17 #include <stddef.h>
18 #include <stdint.h>
19 
20 #include <memory>
21 #include <string>
22 
23 #include "base/check.h"
24 #include "base/containers/span.h"
25 #include "net/base/net_export.h"
26 #include "net/ntlm/ntlm_constants.h"
27 
28 namespace net::ntlm {
29 
30 // Provides an implementation of an NTLMv1 or NTLMv2 Client with support
31 // for MIC and EPA [1]. This implementation does not support the key exchange,
32 // signing or sealing feature as the NTLMSSP_NEGOTIATE_KEY_EXCH flag is never
33 // negotiated.
34 //
35 // [1] -
36 // https://support.microsoft.com/en-us/help/968389/extended-protection-for-authentication
37 class NET_EXPORT_PRIVATE NtlmClient {
38  public:
39   // Pass feature flags to enable/disable NTLMv2 and additional NTLMv2
40   // features such as Extended Protection for Authentication (EPA) and Message
41   // Integrity Check (MIC).
42   explicit NtlmClient(NtlmFeatures features);
43 
44   NtlmClient(const NtlmClient&) = delete;
45   NtlmClient& operator=(const NtlmClient&) = delete;
46 
47   ~NtlmClient();
48 
IsNtlmV2()49   bool IsNtlmV2() const { return features_.enable_NTLMv2; }
50 
IsMicEnabled()51   bool IsMicEnabled() const { return IsNtlmV2() && features_.enable_MIC; }
52 
IsEpaEnabled()53   bool IsEpaEnabled() const { return IsNtlmV2() && features_.enable_EPA; }
54 
55   // Returns the Negotiate message.
56   std::vector<uint8_t> GetNegotiateMessage() const;
57 
58   // Returns a the Authenticate message. If the method fails an empty vector
59   // is returned.
60   //
61   // |username| is treated case insensitively by NTLM however the mechanism
62   // to uppercase is not clearly defined. In this implementation the default
63   // locale is used. Additionally for names longer than 20 characters, the
64   // fully qualified name in the new '@' format must be used.
65   // eg. very_long_name@domain.com. Names shorter than 20 characters can
66   // optionally omit the '@domain.com' part.
67   // |hostname| can be a short NetBIOS name or an FQDN, however the server will
68   // only inspect this field if the default domain policy is to restrict NTLM.
69   // In this case the hostname will be compared to an allowlist stored in this
70   // group policy [1].
71   // |channel_bindings| is a string supplied out of band (usually from a web
72   // browser) and is a (21+sizeof(hash)) byte ASCII string, where 'hash' is
73   // usually a SHA-256 of the servers certificate, but may be another hash
74   // algorithm. The format as defined by RFC 5929 Section 4 is shown below;
75   //
76   // [0-20]                 - "tls-server-end-point:"   (Literal string)
77   // [21-(20+sizeof(hash)]  - HASH(server_certificate)  (Certificate hash)
78   //
79   // |spn| is a string supplied out of band (usually from a web browser) and
80   // is a Service  Principal Name [2]. For NTLM over HTTP the value of this
81   // string will usually be "HTTP/<hostname>".
82   // |client_time| 64 bit Windows timestamp defined as the number of
83   // 100 nanosecond ticks since midnight Jan 01, 1601 (UTC). If the server does
84   // not send a timestamp, the client timestamp is used in the Proof Input
85   // instead.
86   // |server_challenge_message| is the full content of the challenge message
87   // sent by the server.
88   //
89   // [1] - https://technet.microsoft.com/en-us/library/jj852267(v=ws.11).aspx
90   std::vector<uint8_t> GenerateAuthenticateMessage(
91       const std::u16string& domain,
92       const std::u16string& username,
93       const std::u16string& password,
94       const std::string& hostname,
95       const std::string& channel_bindings,
96       const std::string& spn,
97       uint64_t client_time,
98       base::span<const uint8_t, kChallengeLen> client_challenge,
99       base::span<const uint8_t> server_challenge_message) const;
100 
101   // Simplified method for NTLMv1 which does not require |channel_bindings|,
102   // |spn|, or |client_time|. See |GenerateAuthenticateMessage| for more
103   // details.
GenerateAuthenticateMessageV1(const std::u16string & domain,const std::u16string & username,const std::u16string & password,const std::string & hostname,base::span<const uint8_t,8> client_challenge,base::span<const uint8_t> server_challenge_message)104   std::vector<uint8_t> GenerateAuthenticateMessageV1(
105       const std::u16string& domain,
106       const std::u16string& username,
107       const std::u16string& password,
108       const std::string& hostname,
109       base::span<const uint8_t, 8> client_challenge,
110       base::span<const uint8_t> server_challenge_message) const {
111     DCHECK(!IsNtlmV2());
112 
113     return GenerateAuthenticateMessage(
114         domain, username, password, hostname, std::string(), std::string(), 0,
115         client_challenge, server_challenge_message);
116   }
117 
118  private:
119   // Returns the length of the Authenticate message based on the length of the
120   // variable length parts of the message and whether Unicode support was
121   // negotiated.
122   size_t CalculateAuthenticateMessageLength(
123       bool is_unicode,
124       const std::u16string& domain,
125       const std::u16string& username,
126       const std::string& hostname,
127       size_t updated_target_info_len) const;
128 
129   bool CalculatePayloadLayout(bool is_unicode,
130                               const std::u16string& domain,
131                               const std::u16string& username,
132                               const std::string& hostname,
133                               size_t updated_target_info_len,
134                               SecurityBuffer* lm_info,
135                               SecurityBuffer* ntlm_info,
136                               SecurityBuffer* domain_info,
137                               SecurityBuffer* username_info,
138                               SecurityBuffer* hostname_info,
139                               SecurityBuffer* session_key_info,
140                               size_t* authenticate_message_len) const;
141 
142   // Returns the length of the header part of the Authenticate message.
143   size_t GetAuthenticateHeaderLength() const;
144 
145   // Returns the length of the NTLM response.
146   size_t GetNtlmResponseLength(size_t updated_target_info_len) const;
147 
148   // Generates the negotiate message (which is always the same) into
149   // |negotiate_message_|.
150   void GenerateNegotiateMessage();
151 
152   const NtlmFeatures features_;
153   NegotiateFlags negotiate_flags_;
154   std::vector<uint8_t> negotiate_message_;
155 };
156 
157 }  // namespace net::ntlm
158 
159 #endif  // NET_NTLM_NTLM_CLIENT_H_
160