summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMili Verma <mili.verma@isode.com>2015-06-26 14:32:04 (GMT)
committerMili Verma <mili.verma@isode.com>2015-06-30 09:47:58 (GMT)
commit208c75672fa106fe6e3a44bcb41dc9f2808b1b71 (patch)
tree973c70b4711bc1e27c3877c89f9e15d761a1210e /Swiften/SASL/WindowsAuthentication.cpp
parenta3564b7aca44f5ccab3881e6f723dfb64bf66884 (diff)
downloadswift-208c75672fa106fe6e3a44bcb41dc9f2808b1b71.zip
swift-208c75672fa106fe6e3a44bcb41dc9f2808b1b71.tar.bz2
Add wrappers for Windows API to be used in GSSAPI
Test-information: Tested on Windows using WIP GSSAPI code. Unit tests pass. Change-Id: I21f8f637480a21a014ec172431dd8d4a01a11620
Diffstat (limited to 'Swiften/SASL/WindowsAuthentication.cpp')
-rw-r--r--Swiften/SASL/WindowsAuthentication.cpp327
1 files changed, 327 insertions, 0 deletions
diff --git a/Swiften/SASL/WindowsAuthentication.cpp b/Swiften/SASL/WindowsAuthentication.cpp
new file mode 100644
index 0000000..0244fe1
--- /dev/null
+++ b/Swiften/SASL/WindowsAuthentication.cpp
@@ -0,0 +1,327 @@
1/*
2 * Copyright (c) 2015 Isode Limited.
3 * All rights reserved.
4 * See the COPYING file for more information.
5 */
6
7#include <Swiften/SASL/WindowsAuthentication.h>
8
9#include <iomanip>
10
11#include <Secext.h>
12
13#include <Swiften/Base/Log.h>
14#include <Swiften/Base/String.h>
15
16#define ASSIGN_ERROR(status, errorCode) \
17{ \
18 errorCode = boost::make_shared<boost::system::error_code>(status, boost::system::system_category()); \
19 SWIFT_LOG(debug) << std::hex << "status: 0x" << status << ": " << errorCode->message() << std::endl; \
20}
21
22#define ASSIGN_SEC_ERROR(status, errorCode) \
23{ \
24 if (status == SEC_E_OK) \
25 { \
26 SWIFT_LOG(debug) << "success" << std::endl; \
27 } \
28 else { \
29 ASSIGN_ERROR(status, errorCode); \
30 } \
31}
32
33namespace Swift {
34
35boost::shared_ptr<boost::system::error_code> getUserNameEx(std::string& userName, std::string& clientName, std::string& serverName) {
36 ULONG length = 512;
37 DWORD status = ERROR_MORE_DATA;
38 bool firstCall = true;
39 boost::shared_ptr<boost::system::error_code> errorCode;
40
41 while (status == ERROR_MORE_DATA) {
42 std::vector<wchar_t> value(length);
43
44 /* length after this call will contain the required length if current length is not enough - so the next call should succeed */
45 if (GetUserNameExW(NameSamCompatible, vecptr(value), &length)) {
46 std::size_t position;
47
48 userName = convertWStringToString(std::wstring(vecptr(value), length));
49 SWIFT_LOG(debug) << "User Name: " << userName << std::endl;
50
51 position = userName.find("\\");
52 clientName = userName.substr(position + 1);
53 SWIFT_LOG(debug) << "Client name: " << clientName << std::endl;
54
55 serverName = userName.substr(0, position);
56 SWIFT_LOG(debug) << "Server name: " << serverName << std::endl;
57
58 break;
59 }
60
61 status = GetLastError();
62 if ((firstCall == false) || (status != ERROR_MORE_DATA)) {
63 ASSIGN_ERROR(status, errorCode);
64 break;
65 }
66
67 firstCall = false;
68 }
69
70 return errorCode;
71}
72
73boost::shared_ptr<boost::system::error_code> acquireCredentialsHandle(PCredHandle credentialsHandle) {
74 SECURITY_STATUS status;
75 boost::shared_ptr<boost::system::error_code> errorCode;
76 TimeStamp validity;
77
78 status = AcquireCredentialsHandle(
79 NULL, /* NULL indicates credentials of the user under whose security context it is executing */
80 "Kerberos",
81 SECPKG_CRED_OUTBOUND, /* client credential */
82 NULL,
83 NULL, /* use default credentials */
84 NULL, /* not used */
85 NULL, /* not used */
86 credentialsHandle,
87 &validity);
88 ASSIGN_SEC_ERROR(status, errorCode);
89
90 return errorCode;
91}
92
93boost::shared_ptr<boost::system::error_code> freeCredentialsHandle(PCredHandle credentialsHandle) {
94 SECURITY_STATUS status;
95 boost::shared_ptr<boost::system::error_code> errorCode;
96
97 status = FreeCredentialsHandle(credentialsHandle);
98 ASSIGN_SEC_ERROR(status, errorCode);
99
100 return errorCode;
101}
102
103boost::shared_ptr<boost::system::error_code> initializeSecurityContext(const boost::optional<ByteArray>& inputToken, const std::string& servicePrincipalNameString, const PCredHandle credentialsHandle, bool haveContextHandle, PCtxtHandle contextHandle, ULONG contextRequested, ULONG* contextSupported, bool* haveCompleteContext, SafeByteArray& outputToken) {
104 SECURITY_STATUS status;
105 boost::shared_ptr<boost::system::error_code> errorCode;
106 SecBufferDesc input;
107 SecBufferDesc output;
108 SecBuffer inputTokenBuffer;
109 SecBuffer outputTokenBuffer;
110 TimeStamp validity;
111
112 *haveCompleteContext = false;
113
114 input.ulVersion = 0;
115 input.cBuffers = 1;
116 input.pBuffers = &inputTokenBuffer;
117
118 inputTokenBuffer.BufferType = SECBUFFER_TOKEN;
119 inputTokenBuffer.cbBuffer = 0;
120 inputTokenBuffer.pvBuffer = NULL;
121 if (inputToken && inputToken->size()) {
122 inputTokenBuffer.cbBuffer = inputToken->size();
123 inputTokenBuffer.pvBuffer = (void *) vecptr(*inputToken);
124 }
125
126 output.ulVersion = 0;
127 output.cBuffers = 1;
128 output.pBuffers = &outputTokenBuffer;
129
130 outputTokenBuffer.BufferType = SECBUFFER_TOKEN;
131 outputTokenBuffer.cbBuffer = 0;
132 outputTokenBuffer.pvBuffer = NULL;
133
134 status = InitializeSecurityContext(
135 credentialsHandle, /* previously acquired handle */
136 haveContextHandle ? contextHandle : NULL, /* use partial context on subsequent calls */
137 const_cast<char *>(servicePrincipalNameString.c_str()),
138 contextRequested | ISC_REQ_ALLOCATE_MEMORY,
139 0, /* not used */
140 SECURITY_NETWORK_DREP,
141 haveContextHandle ? &input : NULL,
142 0, /* not used */
143 contextHandle,
144 &output,
145 contextSupported,
146 &validity);
147 ASSIGN_SEC_ERROR(status, errorCode); /* errorCode set here will only be returned to caller if there was a non-success status */
148 if ((status == SEC_I_COMPLETE_AND_CONTINUE) || (status == SEC_I_COMPLETE_NEEDED)) {
149 /* The Windows documentation suggests that this function is used only for Digest and only on the server side, but still asks to call this function for Kerberos clients. Most likely this function will never be called, but including it for compliance with documentation. */
150 errorCode = completeAuthToken(contextHandle, &output);
151 if (!errorCode) {
152 /* success, move on */
153 }
154 else {
155 freeContextBuffer(outputTokenBuffer.pvBuffer);
156 return errorCode;
157 }
158 }
159 if ((status == SEC_E_OK) || (status == SEC_I_COMPLETE_NEEDED)) {
160 *haveCompleteContext = true;
161 }
162 if ((status == SEC_E_OK) || (status == SEC_I_COMPLETE_AND_CONTINUE) || (status == SEC_I_COMPLETE_NEEDED) || (status == SEC_I_CONTINUE_NEEDED)) {
163 outputToken = createSafeByteArray (static_cast<unsigned char *>(outputTokenBuffer.pvBuffer), outputTokenBuffer.cbBuffer);
164 SWIFT_LOG(debug) << "outputToken.size(): " << outputToken.size() << std::endl;
165 freeContextBuffer(outputTokenBuffer.pvBuffer);
166
167 return boost::shared_ptr<boost::system::error_code>(); /* success */
168 }
169
170 return errorCode;
171}
172
173boost::shared_ptr<boost::system::error_code> deleteSecurityContext(PCtxtHandle contextHandle) {
174 SECURITY_STATUS status;
175 boost::shared_ptr<boost::system::error_code> errorCode;
176
177 status = DeleteSecurityContext(contextHandle);
178 ASSIGN_SEC_ERROR(status, errorCode);
179
180 return errorCode;
181}
182
183boost::shared_ptr<boost::system::error_code> completeAuthToken(const PCtxtHandle contextHandle, PSecBufferDesc token) {
184 SECURITY_STATUS status;
185 boost::shared_ptr<boost::system::error_code> errorCode;
186
187 status = CompleteAuthToken(
188 contextHandle, /* partial context */
189 token);
190 ASSIGN_SEC_ERROR(status, errorCode);
191
192 return errorCode;
193}
194
195boost::shared_ptr<boost::system::error_code> freeContextBuffer(PVOID contextBuffer) {
196 SECURITY_STATUS status;
197 boost::shared_ptr<boost::system::error_code> errorCode;
198
199 if (contextBuffer == NULL) {
200 return errorCode;
201 }
202
203 status = FreeContextBuffer(contextBuffer);
204 ASSIGN_SEC_ERROR(status, errorCode);
205
206 return errorCode;
207}
208
209boost::shared_ptr<boost::system::error_code> decryptMessage(const PCtxtHandle contextHandle, const ByteArray& message, SafeByteArray& decrypted) {
210 /* Following https://msdn.microsoft.com/en-us/library/windows/desktop/aa380496%28v=vs.85%29.aspx */
211
212 SECURITY_STATUS status;
213 boost::shared_ptr<boost::system::error_code> errorCode;
214 SecBufferDesc inOut;
215 SecBuffer messageBuffer[2];
216 SafeByteArray inputMessage;
217 ULONG qualityOfProtection;
218
219 inOut.ulVersion = SECBUFFER_VERSION;
220 inOut.cBuffers = 2;
221 inOut.pBuffers = messageBuffer;
222
223 inputMessage = createSafeByteArray (message); /* Make a copy as DecryptMessage decrypts the input in place, overwriting it */
224 messageBuffer[0].BufferType = SECBUFFER_STREAM;
225 messageBuffer[0].cbBuffer = inputMessage.size();
226 messageBuffer[0].pvBuffer = static_cast<void *>(vecptr(inputMessage));
227
228 messageBuffer[1].BufferType = SECBUFFER_DATA;
229 messageBuffer[1].cbBuffer = 0;
230 messageBuffer[1].pvBuffer = NULL;
231
232 SWIFT_LOG(debug) << "inputMessage.size(): " << inputMessage.size() << std::endl;
233
234 status = DecryptMessage(
235 contextHandle,
236 &inOut,
237 0, /* Don't maintain sequence numbers */
238 &qualityOfProtection);
239 ASSIGN_SEC_ERROR(status, errorCode);
240 if (status == SEC_E_OK) {
241 if (qualityOfProtection == SECQOP_WRAP_NO_ENCRYPT) {
242 SWIFT_LOG(debug) << "Message was signed only" << std::endl;
243 }
244 else {
245 SWIFT_LOG(debug) << "Message was encrypted" << std::endl;
246 }
247
248 SWIFT_LOG(debug) << "messageBuffer[1].cbBuffer: " << messageBuffer[1].cbBuffer << std::endl;
249
250 decrypted = createSafeByteArray (static_cast<unsigned char *>(messageBuffer[1].pvBuffer), messageBuffer[1].cbBuffer);
251 }
252
253 return errorCode;
254}
255
256boost::shared_ptr<boost::system::error_code> encryptMessage(const PCtxtHandle contextHandle, const SecPkgContext_Sizes& sizes, const SafeByteArray& message, SafeByteArray& output) {
257 /* Following https://msdn.microsoft.com/en-us/library/windows/desktop/aa380496%28v=vs.85%29.aspx */
258
259 SECURITY_STATUS status;
260 boost::shared_ptr<boost::system::error_code> errorCode;
261 SecBufferDesc inOut;
262 SecBuffer messageBuffer[3];
263 SafeByteArray securityTrailer(sizes.cbSecurityTrailer);
264 SafeByteArray blockSize(sizes.cbBlockSize);
265 SafeByteArray inputMessage;
266
267 inOut.ulVersion = SECBUFFER_VERSION;
268 inOut.cBuffers = 3;
269 inOut.pBuffers = messageBuffer;
270
271 messageBuffer[0].BufferType = SECBUFFER_TOKEN;
272 messageBuffer[0].cbBuffer = sizes.cbSecurityTrailer;
273 messageBuffer[0].pvBuffer = vecptr(securityTrailer);
274
275 inputMessage = createSafeByteArray (vecptr(message), message.size()); /* Make a copy as EncryptMessage encrypts the input in place, overwriting it */
276 messageBuffer[1].BufferType = SECBUFFER_DATA;
277 messageBuffer[1].cbBuffer = inputMessage.size();
278 messageBuffer[1].pvBuffer = (void *) vecptr(inputMessage);
279
280 messageBuffer[2].BufferType = SECBUFFER_PADDING;
281 messageBuffer[2].cbBuffer = sizes.cbBlockSize;
282 messageBuffer[2].pvBuffer = vecptr(blockSize);
283
284 SWIFT_LOG(debug) << "sizes.cbSecurityTrailer: " << sizes.cbSecurityTrailer << std::endl;
285 SWIFT_LOG(debug) << "inputMessage.size(): " << inputMessage.size() << std::endl;
286 SWIFT_LOG(debug) << "sizes.cbBlockSize: " << sizes.cbBlockSize << std::endl;
287
288 status = EncryptMessage(
289 contextHandle,
290 SECQOP_WRAP_NO_ENCRYPT,
291 &inOut,
292 0); /* Don't maintain sequence numbers */
293 ASSIGN_SEC_ERROR(status, errorCode);
294 if (status == SEC_E_OK) {
295 unsigned char* pointer;
296
297 SWIFT_LOG(debug) << "messageBuffer[0].cbBuffer: " << messageBuffer[0].cbBuffer << std::endl;
298 SWIFT_LOG(debug) << "messageBuffer[1].cbBuffer: " << messageBuffer[1].cbBuffer << std::endl;
299 SWIFT_LOG(debug) << "messageBuffer[2].cbBuffer: " << messageBuffer[2].cbBuffer << std::endl;
300
301 output.resize(messageBuffer[0].cbBuffer + messageBuffer[1].cbBuffer + messageBuffer[2].cbBuffer);
302 pointer = vecptr(output);
303 for (size_t i = 0; i < inOut.cBuffers; i++) {
304 if (messageBuffer[i].cbBuffer) {
305 memcpy(pointer, messageBuffer[i].pvBuffer, messageBuffer[i].cbBuffer);
306 pointer += messageBuffer[i].cbBuffer;
307 }
308 }
309 }
310
311 return errorCode;
312}
313
314boost::shared_ptr<boost::system::error_code> queryContextAttributes(const PCtxtHandle contextHandle, ULONG attribute, PVOID buffer) {
315 SECURITY_STATUS status;
316 boost::shared_ptr<boost::system::error_code> errorCode;
317
318 status = QueryContextAttributes(
319 contextHandle,
320 attribute,
321 buffer);
322 ASSIGN_SEC_ERROR(status, errorCode);
323
324 return errorCode;
325}
326
327}