1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // This file contains common routines used by NTLM and Negotiate authentication
6 // using the SSPI API on Windows.
7 
8 #ifndef NET_HTTP_HTTP_AUTH_SSPI_WIN_H_
9 #define NET_HTTP_HTTP_AUTH_SSPI_WIN_H_
10 
11 // security.h needs to be included for CredHandle. Unfortunately CredHandle
12 // is a typedef and can't be forward declared.
13 #define SECURITY_WIN32 1
14 #include <windows.h>
15 #include <security.h>
16 
17 #include <string>
18 
19 #include "base/strings/string16.h"
20 #include "net/base/completion_once_callback.h"
21 #include "net/base/net_errors.h"
22 #include "net/base/net_export.h"
23 #include "net/http/http_auth.h"
24 #include "net/http/http_auth_mechanism.h"
25 
26 namespace net {
27 
28 class HttpAuthChallengeTokenizer;
29 
30 // SSPILibrary is introduced so unit tests can mock the calls to Windows' SSPI
31 // implementation. The default implementation simply passes the arguments on to
32 // the SSPI implementation provided by Secur32.dll.
33 //
34 // A single SSPILibrary can only be used with a single security package. Hence
35 // the package is bound at construction time. Overridable SSPI methods exclude
36 // the security package parameter since it is implicit.
37 class NET_EXPORT_PRIVATE SSPILibrary {
38  public:
SSPILibrary(const wchar_t * package)39   explicit SSPILibrary(const wchar_t* package) : package_name_(package) {}
~SSPILibrary()40   virtual ~SSPILibrary() {}
41 
42   // Determines the maximum token length in bytes for a particular SSPI package.
43   //
44   // |library| and |max_token_length| must be non-nullptr pointers to valid
45   // objects.
46   //
47   // If the return value is OK, |*max_token_length| contains the maximum token
48   // length in bytes.
49   //
50   // If the return value is ERR_UNSUPPORTED_AUTH_SCHEME, |package| is not an
51   // known SSPI authentication scheme on this system. |*max_token_length| is not
52   // changed.
53   //
54   // If the return value is ERR_UNEXPECTED, there was an unanticipated problem
55   // in the underlying SSPI call. The details are logged, and
56   // |*max_token_length| is not changed.
57   Error DetermineMaxTokenLength(ULONG* max_token_length);
58 
59   virtual SECURITY_STATUS AcquireCredentialsHandle(LPWSTR pszPrincipal,
60                                                    unsigned long fCredentialUse,
61                                                    void* pvLogonId,
62                                                    void* pvAuthData,
63                                                    SEC_GET_KEY_FN pGetKeyFn,
64                                                    void* pvGetKeyArgument,
65                                                    PCredHandle phCredential,
66                                                    PTimeStamp ptsExpiry) = 0;
67 
68   virtual SECURITY_STATUS InitializeSecurityContext(PCredHandle phCredential,
69                                                     PCtxtHandle phContext,
70                                                     SEC_WCHAR* pszTargetName,
71                                                     unsigned long fContextReq,
72                                                     unsigned long Reserved1,
73                                                     unsigned long TargetDataRep,
74                                                     PSecBufferDesc pInput,
75                                                     unsigned long Reserved2,
76                                                     PCtxtHandle phNewContext,
77                                                     PSecBufferDesc pOutput,
78                                                     unsigned long* contextAttr,
79                                                     PTimeStamp ptsExpiry) = 0;
80 
81   virtual SECURITY_STATUS QueryContextAttributesEx(PCtxtHandle phContext,
82                                                    ULONG ulAttribute,
83                                                    PVOID pBuffer,
84                                                    ULONG cbBuffer) = 0;
85 
86   virtual SECURITY_STATUS QuerySecurityPackageInfo(PSecPkgInfoW* pkgInfo) = 0;
87 
88   virtual SECURITY_STATUS FreeCredentialsHandle(PCredHandle phCredential) = 0;
89 
90   virtual SECURITY_STATUS DeleteSecurityContext(PCtxtHandle phContext) = 0;
91 
92   virtual SECURITY_STATUS FreeContextBuffer(PVOID pvContextBuffer) = 0;
93 
94  protected:
95   // Security package used with DetermineMaxTokenLength(),
96   // QuerySecurityPackageInfo(), AcquireCredentialsHandle(). All of these must
97   // be consistent.
98   const std::wstring package_name_;
99   ULONG max_token_length_ = 0;
100 
101   bool is_supported_ = true;
102 };
103 
104 class SSPILibraryDefault : public SSPILibrary {
105  public:
SSPILibraryDefault(const wchar_t * package)106   explicit SSPILibraryDefault(const wchar_t* package) : SSPILibrary(package) {}
~SSPILibraryDefault()107   ~SSPILibraryDefault() override {}
108 
109   SECURITY_STATUS AcquireCredentialsHandle(LPWSTR pszPrincipal,
110                                            unsigned long fCredentialUse,
111                                            void* pvLogonId,
112                                            void* pvAuthData,
113                                            SEC_GET_KEY_FN pGetKeyFn,
114                                            void* pvGetKeyArgument,
115                                            PCredHandle phCredential,
116                                            PTimeStamp ptsExpiry) override;
117 
118   SECURITY_STATUS InitializeSecurityContext(PCredHandle phCredential,
119                                             PCtxtHandle phContext,
120                                             SEC_WCHAR* pszTargetName,
121                                             unsigned long fContextReq,
122                                             unsigned long Reserved1,
123                                             unsigned long TargetDataRep,
124                                             PSecBufferDesc pInput,
125                                             unsigned long Reserved2,
126                                             PCtxtHandle phNewContext,
127                                             PSecBufferDesc pOutput,
128                                             unsigned long* contextAttr,
129                                             PTimeStamp ptsExpiry) override;
130 
131   SECURITY_STATUS QueryContextAttributesEx(PCtxtHandle phContext,
132                                            ULONG ulAttribute,
133                                            PVOID pBuffer,
134                                            ULONG cbBuffer) override;
135 
136   SECURITY_STATUS QuerySecurityPackageInfo(PSecPkgInfoW* pkgInfo) override;
137 
138   SECURITY_STATUS FreeCredentialsHandle(PCredHandle phCredential) override;
139 
140   SECURITY_STATUS DeleteSecurityContext(PCtxtHandle phContext) override;
141 
142   SECURITY_STATUS FreeContextBuffer(PVOID pvContextBuffer) override;
143 };
144 
145 class NET_EXPORT_PRIVATE HttpAuthSSPI : public HttpAuthMechanism {
146  public:
147   HttpAuthSSPI(SSPILibrary* sspi_library, HttpAuth::Scheme scheme);
148   ~HttpAuthSSPI() override;
149 
150   // HttpAuthMechanism implementation:
151   bool Init(const NetLogWithSource& net_log) override;
152   bool NeedsIdentity() const override;
153   bool AllowsExplicitCredentials() const override;
154   HttpAuth::AuthorizationResult ParseChallenge(
155       HttpAuthChallengeTokenizer* tok) override;
156   int GenerateAuthToken(const AuthCredentials* credentials,
157                         const std::string& spn,
158                         const std::string& channel_bindings,
159                         std::string* auth_token,
160                         const NetLogWithSource& net_log,
161                         CompletionOnceCallback callback) override;
162   void SetDelegation(HttpAuth::DelegationType delegation_type) override;
163 
164  private:
165   int OnFirstRound(const AuthCredentials* credentials,
166                    const NetLogWithSource& net_log);
167 
168   int GetNextSecurityToken(const std::string& spn,
169                            const std::string& channing_bindings,
170                            const void* in_token,
171                            int in_token_len,
172                            const NetLogWithSource& net_log,
173                            void** out_token,
174                            int* out_token_len);
175 
176   void ResetSecurityContext();
177 
178   SSPILibrary* library_;
179   HttpAuth::Scheme scheme_;
180   std::string decoded_server_auth_token_;
181   CredHandle cred_;
182   CtxtHandle ctxt_;
183   HttpAuth::DelegationType delegation_type_;
184 };
185 
186 // Splits |combined| into domain and username.
187 // If |combined| is of form "FOO\bar", |domain| will contain "FOO" and |user|
188 // will contain "bar".
189 // If |combined| is of form "bar", |domain| will be empty and |user| will
190 // contain "bar".
191 // |domain| and |user| must be non-nullptr.
192 NET_EXPORT_PRIVATE void SplitDomainAndUser(const base::string16& combined,
193                                            base::string16* domain,
194                                            base::string16* user);
195 
196 }  // namespace net
197 
198 #endif  // NET_HTTP_HTTP_AUTH_SSPI_WIN_H_
199