b78c93af82e1cb2d88beb1dc52118e663b07c5a3
[platform/upstream/freerdp.git] / libfreerdp-auth / credssp.c
1 /**
2  * FreeRDP: A Remote Desktop Protocol Implementation
3  * Credential Security Support Provider (CredSSP)
4  *
5  * Copyright 2010-2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *               http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19
20 #ifndef _WIN32
21 #include <unistd.h>
22 #endif
23
24 #include <time.h>
25 #include <freerdp/crypto/tls.h>
26 #include <freerdp/auth/ntlmssp.h>
27 #include <freerdp/utils/stream.h>
28
29 #include <freerdp/auth/sspi.h>
30 #include <freerdp/auth/credssp.h>
31
32 //#define WITH_SSPI             1
33
34 /**
35  * TSRequest ::= SEQUENCE {
36  *      version    [0] INTEGER,
37  *      negoTokens [1] NegoData OPTIONAL,
38  *      authInfo   [2] OCTET STRING OPTIONAL,
39  *      pubKeyAuth [3] OCTET STRING OPTIONAL
40  * }
41  *
42  * NegoData ::= SEQUENCE OF NegoDataItem
43  *
44  * NegoDataItem ::= SEQUENCE {
45  *      negoToken [0] OCTET STRING
46  * }
47  *
48  * TSCredentials ::= SEQUENCE {
49  *      credType    [0] INTEGER,
50  *      credentials [1] OCTET STRING
51  * }
52  *
53  * TSPasswordCreds ::= SEQUENCE {
54  *      domainName  [0] OCTET STRING,
55  *      userName    [1] OCTET STRING,
56  *      password    [2] OCTET STRING
57  * }
58  *
59  * TSSmartCardCreds ::= SEQUENCE {
60  *      pin        [0] OCTET STRING,
61  *      cspData    [1] TSCspDataDetail,
62  *      userHint   [2] OCTET STRING OPTIONAL,
63  *      domainHint [3] OCTET STRING OPTIONAL
64  * }
65  *
66  * TSCspDataDetail ::= SEQUENCE {
67  *      keySpec       [0] INTEGER,
68  *      cardName      [1] OCTET STRING OPTIONAL,
69  *      readerName    [2] OCTET STRING OPTIONAL,
70  *      containerName [3] OCTET STRING OPTIONAL,
71  *      cspName       [4] OCTET STRING OPTIONAL
72  * }
73  *
74  */
75
76 /**
77  * Initialize NTLMSSP authentication module (client).
78  * @param credssp
79  */
80
81 int credssp_ntlmssp_client_init(rdpCredssp* credssp)
82 {
83         freerdp* instance;
84         NTLMSSP* ntlmssp = credssp->ntlmssp;
85         rdpSettings* settings = credssp->settings;
86         instance = (freerdp*) settings->instance;
87
88         if ((settings->password == NULL) || (settings->username == NULL))
89         {
90                 if (instance->Authenticate)
91                 {
92                         boolean proceed = instance->Authenticate(instance,
93                                         &settings->username, &settings->password, &settings->domain);
94                         if (!proceed)
95                                 return 0;
96                 }
97         }
98
99         if (settings->ntlm_version == 2)
100                 ntlmssp->ntlm_v2 = 1;
101
102         ntlmssp_set_password(ntlmssp, settings->password);
103         ntlmssp_set_username(ntlmssp, settings->username);
104
105         if (ntlmssp->ntlm_v2)
106         {
107                 ntlmssp_set_workstation(ntlmssp, "WORKSTATION");
108         }
109
110         if (settings->domain != NULL)
111         {
112                 if (strlen(settings->domain) > 0)
113                         ntlmssp_set_domain(ntlmssp, settings->domain);
114         }
115         else
116         {
117                 ntlmssp_set_domain(ntlmssp, NULL);
118         }
119
120         ntlmssp_generate_client_challenge(ntlmssp);
121         ntlmssp_generate_random_session_key(ntlmssp);
122         ntlmssp_generate_exported_session_key(ntlmssp);
123
124         return 1;
125 }
126
127 /**
128  * Initialize NTLMSSP authentication module (server).
129  * @param credssp
130  */
131
132 int credssp_ntlmssp_server_init(rdpCredssp* credssp)
133 {
134         NTLMSSP* ntlmssp = credssp->ntlmssp;
135
136         ntlmssp_generate_server_challenge(ntlmssp);
137
138         return 1;
139 }
140
141 /**
142  * Authenticate with server using CredSSP (client).
143  * @param credssp
144  * @return 1 if authentication is successful
145  */
146
147 #ifndef WITH_SSPI
148
149 int credssp_client_authenticate(rdpCredssp* credssp)
150 {
151         NTLMSSP* ntlmssp = credssp->ntlmssp;
152         STREAM* s = stream_new(0);
153         uint8* negoTokenBuffer = (uint8*) xmalloc(2048);
154
155         if (credssp_ntlmssp_client_init(credssp) == 0)
156                 return 0;
157
158         /* NTLMSSP NEGOTIATE MESSAGE */
159         stream_attach(s, negoTokenBuffer, 2048);
160         ntlmssp_send(ntlmssp, s);
161         credssp->negoToken.data = stream_get_head(s);
162         credssp->negoToken.length = stream_get_length(s);
163         credssp_send(credssp, &credssp->negoToken, NULL, NULL);
164
165         /* NTLMSSP CHALLENGE MESSAGE */
166         if (credssp_recv(credssp, &credssp->negoToken, NULL, NULL) < 0)
167                 return -1;
168
169         stream_attach(s, credssp->negoToken.data, credssp->negoToken.length);
170         ntlmssp_recv(ntlmssp, s);
171
172         freerdp_blob_free(&credssp->negoToken);
173
174         /* NTLMSSP AUTHENTICATE MESSAGE */
175         stream_attach(s, negoTokenBuffer, 2048);
176         ntlmssp_send(ntlmssp, s);
177
178         /* The last NTLMSSP message is sent with the encrypted public key */
179         credssp->negoToken.data = stream_get_head(s);
180         credssp->negoToken.length = stream_get_length(s);
181         credssp_encrypt_public_key(credssp, &credssp->pubKeyAuth);
182         credssp_send(credssp, &credssp->negoToken, NULL, &credssp->pubKeyAuth);
183         freerdp_blob_free(&credssp->pubKeyAuth);
184
185         /* Encrypted Public Key +1 */
186         if (credssp_recv(credssp, &credssp->negoToken, NULL, &credssp->pubKeyAuth) < 0)
187                 return -1;
188
189         if (credssp_verify_public_key(credssp, &credssp->pubKeyAuth) == 0)
190         {
191                 /* Failed to verify server public key echo */
192                 return 0; /* DO NOT SEND CREDENTIALS! */
193         }
194
195         freerdp_blob_free(&credssp->negoToken);
196         freerdp_blob_free(&credssp->pubKeyAuth);
197
198         /* Send encrypted credentials */
199         credssp_encode_ts_credentials(credssp);
200         credssp_encrypt_ts_credentials(credssp, &credssp->authInfo);
201         credssp_send(credssp, NULL, &credssp->authInfo, NULL);
202         freerdp_blob_free(&credssp->authInfo);
203
204         xfree(s);
205
206         return 1;
207 }
208
209 #else
210
211 #define NTLM_PACKAGE_NAME               "NTLM"
212
213 int credssp_client_authenticate(rdpCredssp* credssp)
214 {
215         uint32 cbMaxLen;
216         uint32 fContextReq;
217         CTXT_HANDLE context;
218         uint32 pfContextAttr;
219         SECURITY_STATUS status;
220         CRED_HANDLE credentials;
221         SEC_TIMESTAMP expiration;
222         SEC_PKG_INFO* pPackageInfo;
223         SEC_AUTH_IDENTITY identity;
224         SEC_BUFFER* p_sec_buffer;
225         SEC_BUFFER input_sec_buffer;
226         SEC_BUFFER output_sec_buffer;
227         SEC_BUFFER_DESC input_sec_buffer_desc;
228         SEC_BUFFER_DESC output_sec_buffer_desc;
229         boolean have_context;
230         boolean have_input_buffer;
231         boolean have_pub_key_auth;
232         SECURITY_FUNCTION_TABLE* table;
233         rdpSettings* settings = credssp->settings;
234
235         sspi_GlobalInit();
236
237         if (credssp_ntlmssp_client_init(credssp) == 0)
238                 return 0;
239
240         table = InitSecurityInterface();
241
242         status = QuerySecurityPackageInfo(NTLM_PACKAGE_NAME, &pPackageInfo);
243
244         if (status != SEC_E_OK)
245         {
246                 printf("QuerySecurityPackageInfo status: 0x%08X\n", status);
247                 return 0;
248         }
249
250         cbMaxLen = pPackageInfo->cbMaxToken;
251
252         identity.User = (uint16*) xstrdup(settings->username);
253         identity.UserLength = strlen(settings->username);
254
255         if (settings->domain)
256         {
257                 identity.Domain = (uint16*) xstrdup(settings->domain);
258                 identity.DomainLength = strlen(settings->domain);
259         }
260         else
261         {
262                 identity.Domain = (uint16*) NULL;
263                 identity.DomainLength = 0;
264         }
265
266         identity.Password = (uint16*) xstrdup(settings->password);
267         identity.PasswordLength = strlen(settings->password);
268
269         identity.Flags = SEC_AUTH_IDENTITY_ANSI;
270
271         status = table->AcquireCredentialsHandle(NULL, NTLM_PACKAGE_NAME,
272                         SECPKG_CRED_OUTBOUND, NULL, &identity, NULL, NULL, &credentials, &expiration);
273
274         if (status != SEC_E_OK)
275         {
276                 printf("AcquireCredentialsHandle status: 0x%08X\n", status);
277                 return 0;
278         }
279
280         have_context = false;
281         have_input_buffer = false;
282         have_pub_key_auth = false;
283         memset(&input_sec_buffer, 0, sizeof(SEC_BUFFER));
284         memset(&output_sec_buffer, 0, sizeof(SEC_BUFFER));
285
286         fContextReq = ISC_REQ_REPLAY_DETECT | ISC_REQ_SEQUENCE_DETECT |
287                         ISC_REQ_CONFIDENTIALITY | ISC_REQ_DELEGATE;
288
289         while (true)
290         {
291                 output_sec_buffer_desc.ulVersion = SECBUFFER_VERSION;
292                 output_sec_buffer_desc.cBuffers = 1;
293                 output_sec_buffer_desc.pBuffers = &output_sec_buffer;
294                 output_sec_buffer.BufferType = SECBUFFER_TOKEN;
295                 output_sec_buffer.cbBuffer = cbMaxLen;
296                 output_sec_buffer.pvBuffer = xmalloc(output_sec_buffer.cbBuffer);
297
298                 status = table->InitializeSecurityContext(&credentials,
299                                 (have_context) ? &context : NULL,
300                                 NULL, fContextReq, 0, SECURITY_NATIVE_DREP,
301                                 (have_input_buffer) ? &input_sec_buffer_desc : NULL,
302                                 0, &context, &output_sec_buffer_desc, &pfContextAttr, &expiration);
303
304                 if (input_sec_buffer.pvBuffer != NULL)
305                 {
306                         xfree(input_sec_buffer.pvBuffer);
307                         input_sec_buffer.pvBuffer = NULL;
308                 }
309
310                 if ((status == SEC_I_COMPLETE_AND_CONTINUE) || (status == SEC_I_COMPLETE_NEEDED))
311                 {
312                         if (table->CompleteAuthToken != NULL)
313                                 table->CompleteAuthToken(&context, &output_sec_buffer_desc);
314
315                         have_pub_key_auth = true;
316
317                         if (have_pub_key_auth)
318                         {
319                                 uint8* p;
320                                 SEC_BUFFER Buffers[2];
321                                 SEC_BUFFER_DESC Message;
322
323                                 Buffers[0].BufferType = SECBUFFER_DATA; /* TLS Public Key */
324                                 Buffers[1].BufferType = SECBUFFER_PADDING; /* Signature */
325
326                                 Buffers[0].cbBuffer = credssp->tls->public_key.length;
327                                 Buffers[0].pvBuffer = xmalloc(Buffers[0].cbBuffer);
328                                 memcpy(Buffers[0].pvBuffer, credssp->tls->public_key.data, Buffers[0].cbBuffer);
329
330                                 Buffers[1].cbBuffer = 16;
331                                 Buffers[1].pvBuffer = xzalloc(Buffers[1].cbBuffer);
332
333                                 Message.cBuffers = 2;
334                                 Message.ulVersion = SECBUFFER_VERSION;
335                                 Message.pBuffers = (SEC_BUFFER*) &Buffers;
336
337                                 freerdp_blob_alloc(&credssp->pubKeyAuth, Buffers[0].cbBuffer + Buffers[1].cbBuffer);
338
339                                 table->EncryptMessage(&context, 0, &Message, 0);
340
341                                 p = (uint8*) credssp->pubKeyAuth.data;
342                                 memcpy(p, Buffers[1].pvBuffer, Buffers[1].cbBuffer); /* Message Signature */
343                                 memcpy(&p[Buffers[1].cbBuffer], Buffers[0].pvBuffer, Buffers[0].cbBuffer); /* Encrypted Public Key */
344                         }
345
346                         if (status == SEC_I_COMPLETE_NEEDED)
347                                 status = SEC_E_OK;
348                         else if (status == SEC_I_COMPLETE_AND_CONTINUE)
349                                 status = SEC_I_CONTINUE_NEEDED;
350                 }
351
352                 /* send authentication token to server */
353
354                 if (output_sec_buffer.cbBuffer > 0)
355                 {
356                         p_sec_buffer = &output_sec_buffer_desc.pBuffers[0];
357
358                         credssp->negoToken.data = p_sec_buffer->pvBuffer;
359                         credssp->negoToken.length = p_sec_buffer->cbBuffer;
360
361                         printf("Sending Authentication Token\n");
362                         freerdp_hexdump(credssp->negoToken.data, credssp->negoToken.length);
363
364                         credssp_send(credssp, &credssp->negoToken, NULL,
365                                         (have_pub_key_auth) ? &credssp->pubKeyAuth : NULL);
366
367                         if (have_pub_key_auth)
368                         {
369                                 have_pub_key_auth = false;
370                                 freerdp_blob_free(&credssp->pubKeyAuth);
371                         }
372
373                         xfree(output_sec_buffer.pvBuffer);
374                         output_sec_buffer.pvBuffer = NULL;
375                 }
376
377                 if (status != SEC_I_CONTINUE_NEEDED)
378                         break;
379
380                 /* receive server response and place in input buffer */
381
382                 input_sec_buffer_desc.ulVersion = SECBUFFER_VERSION;
383                 input_sec_buffer_desc.cBuffers = 1;
384                 input_sec_buffer_desc.pBuffers = &input_sec_buffer;
385                 input_sec_buffer.BufferType = SECBUFFER_TOKEN;
386
387                 if (credssp_recv(credssp, &credssp->negoToken, NULL, NULL) < 0)
388                         return -1;
389
390                 printf("Receiving Authentication Token\n");
391                 freerdp_hexdump(credssp->negoToken.data, credssp->negoToken.length);
392
393                 p_sec_buffer = &input_sec_buffer_desc.pBuffers[0];
394                 p_sec_buffer->pvBuffer = credssp->negoToken.data;
395                 p_sec_buffer->cbBuffer = credssp->negoToken.length;
396
397                 have_input_buffer = true;
398                 have_context = true;
399         }
400
401         /* Encrypted Public Key +1 */
402         if (credssp_recv(credssp, &credssp->negoToken, NULL, &credssp->pubKeyAuth) < 0)
403                 return -1;
404
405         /* Verify Server Public Key Echo */
406
407         {
408                 int length;
409                 uint32 pfQOP;
410                 uint8* public_key1;
411                 uint8* public_key2;
412                 uint8* pub_key_auth;
413                 int public_key_length;
414                 SEC_BUFFER Buffers[2];
415                 SEC_BUFFER_DESC Message;
416
417                 length = credssp->pubKeyAuth.length;
418                 pub_key_auth = (uint8*) credssp->pubKeyAuth.data;
419                 public_key_length = credssp->tls->public_key.length;
420
421                 Buffers[0].BufferType = SECBUFFER_PADDING; /* Signature */
422                 Buffers[1].BufferType = SECBUFFER_DATA; /* Encrypted TLS Public Key */
423
424                 Buffers[0].cbBuffer = 16;
425                 Buffers[0].pvBuffer = xmalloc(Buffers[0].cbBuffer);
426                 memcpy(Buffers[0].pvBuffer, pub_key_auth, Buffers[0].cbBuffer);
427
428                 Buffers[1].cbBuffer = length - Buffers[0].cbBuffer;
429                 Buffers[1].pvBuffer = xmalloc(Buffers[1].cbBuffer);
430                 memcpy(Buffers[1].pvBuffer, &pub_key_auth[Buffers[0].cbBuffer], Buffers[1].cbBuffer);
431
432                 Message.cBuffers = 2;
433                 Message.ulVersion = SECBUFFER_VERSION;
434                 Message.pBuffers = (SEC_BUFFER*) &Buffers;
435
436                 status = table->DecryptMessage(&context, &Message, 0, &pfQOP);
437
438                 if (status != SEC_E_OK)
439                         return 0;
440
441                 public_key1 = (uint8*) credssp->tls->public_key.data;
442                 public_key2 = (uint8*) Buffers[1].pvBuffer;
443
444                 public_key2[0]--; /* server echos the public key +1 */
445
446                 if (memcmp(public_key1, public_key2, public_key_length) != 0)
447                 {
448                         printf("Could not verify server's public key echo\n");
449
450                         printf("Expected (length = %d):\n", public_key_length);
451                         freerdp_hexdump(public_key1, public_key_length);
452
453                         printf("Actual (length = %d):\n", public_key_length);
454                         freerdp_hexdump(public_key2, public_key_length);
455
456                         return 0; /* DO NOT SEND CREDENTIALS! */
457                 }
458
459                 public_key2[0]++;
460         }
461
462         /* Send encrypted credentials */
463         credssp_encode_ts_credentials(credssp);
464
465         /* Encrypt TSCredentials */
466
467         {
468                 uint8* p;
469                 SEC_BUFFER Buffers[2];
470                 SEC_BUFFER_DESC Message;
471
472                 Buffers[0].BufferType = SECBUFFER_DATA; /* TSCredentials */
473                 Buffers[1].BufferType = SECBUFFER_PADDING; /* Signature */
474
475                 Buffers[0].cbBuffer = credssp->ts_credentials.length;
476                 Buffers[0].pvBuffer = xmalloc(Buffers[0].cbBuffer);
477                 memcpy(Buffers[0].pvBuffer, credssp->ts_credentials.data, Buffers[0].cbBuffer);
478
479                 Buffers[1].cbBuffer = 16;
480                 Buffers[1].pvBuffer = xzalloc(Buffers[1].cbBuffer);
481
482                 Message.cBuffers = 2;
483                 Message.ulVersion = SECBUFFER_VERSION;
484                 Message.pBuffers = (SEC_BUFFER*) &Buffers;
485
486                 freerdp_blob_alloc(&credssp->authInfo, Buffers[0].cbBuffer + Buffers[1].cbBuffer);
487
488                 table->EncryptMessage(&context, 0, &Message, 1);
489
490                 p = (uint8*) credssp->authInfo.data;
491                 memcpy(p, Buffers[1].pvBuffer, Buffers[1].cbBuffer); /* Message Signature */
492                 memcpy(&p[Buffers[1].cbBuffer], Buffers[0].pvBuffer, Buffers[0].cbBuffer); /* Encrypted TSCredentials */
493         }
494
495         credssp_send(credssp, NULL, &credssp->authInfo, NULL);
496
497         freerdp_blob_free(&credssp->negoToken);
498         freerdp_blob_free(&credssp->pubKeyAuth);
499         freerdp_blob_free(&credssp->authInfo);
500
501         FreeCredentialsHandle(&credentials);
502         FreeContextBuffer(pPackageInfo);
503
504         return 1;
505 }
506
507 #endif
508
509 /**
510  * Authenticate with client using CredSSP (server).
511  * @param credssp
512  * @return 1 if authentication is successful
513  */
514
515 int credssp_server_authenticate(rdpCredssp* credssp)
516 {
517         STREAM* s = stream_new(0);
518         NTLMSSP* ntlmssp = credssp->ntlmssp;
519         uint8* negoTokenBuffer = (uint8*) xmalloc(2048);
520
521         if (credssp_ntlmssp_server_init(credssp) == 0)
522                 return 0;
523
524         /* NTLMSSP NEGOTIATE MESSAGE */
525         if (credssp_recv(credssp, &credssp->negoToken, NULL, NULL) < 0)
526                 return -1;
527
528         stream_attach(s, credssp->negoToken.data, credssp->negoToken.length);
529         ntlmssp_recv(ntlmssp, s);
530
531         freerdp_blob_free(&credssp->negoToken);
532
533         /* NTLMSSP CHALLENGE MESSAGE */
534         stream_attach(s, negoTokenBuffer, 2048);
535         ntlmssp_send(ntlmssp, s);
536         credssp->negoToken.data = stream_get_head(s);
537         credssp->negoToken.length = stream_get_length(s);
538         credssp_send(credssp, &credssp->negoToken, NULL, NULL);
539
540         /* NTLMSSP AUTHENTICATE MESSAGE */
541         if (credssp_recv(credssp, &credssp->negoToken, NULL, &credssp->pubKeyAuth) < 0)
542                 return -1;
543
544         stream_attach(s, credssp->negoToken.data, credssp->negoToken.length);
545         ntlmssp_recv(ntlmssp, s);
546
547         return 1;
548 }
549
550 /**
551  * Authenticate using CredSSP.
552  * @param credssp
553  * @return 1 if authentication is successful
554  */
555
556 int credssp_authenticate(rdpCredssp* credssp)
557 {
558         if (credssp->server)
559                 return credssp_server_authenticate(credssp);
560         else
561                 return credssp_client_authenticate(credssp);
562 }
563
564 /**
565  * Encrypt TLS public key using CredSSP.
566  * @param credssp
567  * @param s
568  */
569
570 void credssp_encrypt_public_key(rdpCredssp* credssp, rdpBlob* d)
571 {
572         uint8* p;
573         rdpTls* tls;
574         uint8 signature[16];
575         rdpBlob encrypted_public_key;
576         NTLMSSP *ntlmssp = credssp->ntlmssp;
577         tls = credssp->tls;
578
579         freerdp_blob_alloc(d, tls->public_key.length + 16);
580         ntlmssp_encrypt_message(ntlmssp, &tls->public_key, &encrypted_public_key, signature);
581
582 #ifdef WITH_DEBUG_NLA
583         printf("Public Key (length = %d)\n", tls->public_key.length);
584         freerdp_hexdump(tls->public_key.data, tls->public_key.length);
585         printf("\n");
586
587         printf("Encrypted Public Key (length = %d)\n", encrypted_public_key.length);
588         freerdp_hexdump(encrypted_public_key.data, encrypted_public_key.length);
589         printf("\n");
590
591         printf("Signature\n");
592         freerdp_hexdump(signature, 16);
593         printf("\n");
594 #endif
595
596         p = (uint8*) d->data;
597         memcpy(p, signature, 16); /* Message Signature */
598         memcpy(&p[16], encrypted_public_key.data, encrypted_public_key.length); /* Encrypted Public Key */
599
600         freerdp_blob_free(&encrypted_public_key);
601 }
602
603 /**
604  * Verify TLS public key using CredSSP.
605  * @param credssp
606  * @param s
607  * @return 1 if verification is successful, 0 otherwise
608  */
609
610 int credssp_verify_public_key(rdpCredssp* credssp, rdpBlob* d)
611 {
612         uint8 *p1, *p2;
613         uint8* signature;
614         rdpBlob public_key;
615         rdpBlob encrypted_public_key;
616         rdpTls* tls = credssp->tls;
617
618         signature = d->data;
619         encrypted_public_key.data = (void*) (signature + 16);
620         encrypted_public_key.length = d->length - 16;
621
622         ntlmssp_decrypt_message(credssp->ntlmssp, &encrypted_public_key, &public_key, signature);
623
624         p1 = (uint8*) tls->public_key.data;
625         p2 = (uint8*) public_key.data;
626
627         p2[0]--;
628
629         if (memcmp(p1, p2, public_key.length) != 0)
630         {
631                 printf("Could not verify server's public key echo\n");
632                 return 0;
633         }
634
635         p2[0]++;
636         freerdp_blob_free(&public_key);
637         return 1;
638 }
639
640 /**
641  * Encrypt and sign TSCredentials structure.
642  * @param credssp
643  * @param s
644  */
645
646 void credssp_encrypt_ts_credentials(rdpCredssp* credssp, rdpBlob* d)
647 {
648         uint8* p;
649         uint8 signature[16];
650         rdpBlob encrypted_ts_credentials;
651         NTLMSSP* ntlmssp = credssp->ntlmssp;
652
653         freerdp_blob_alloc(d, credssp->ts_credentials.length + 16);
654         ntlmssp_encrypt_message(ntlmssp, &credssp->ts_credentials, &encrypted_ts_credentials, signature);
655
656 #ifdef WITH_DEBUG_NLA
657         printf("TSCredentials (length = %d)\n", credssp->ts_credentials.length);
658         freerdp_hexdump(credssp->ts_credentials.data, credssp->ts_credentials.length);
659         printf("\n");
660
661         printf("Encrypted TSCredentials (length = %d)\n", encrypted_ts_credentials.length);
662         freerdp_hexdump(encrypted_ts_credentials.data, encrypted_ts_credentials.length);
663         printf("\n");
664
665         printf("Signature\n");
666         freerdp_hexdump(signature, 16);
667         printf("\n");
668 #endif
669
670         p = (uint8*) d->data;
671         memcpy(p, signature, 16); /* Message Signature */
672         memcpy(&p[16], encrypted_ts_credentials.data, encrypted_ts_credentials.length); /* Encrypted TSCredentials */
673
674         freerdp_blob_free(&encrypted_ts_credentials);
675 }
676
677 int credssp_skip_ts_password_creds(rdpCredssp* credssp)
678 {
679         int length;
680         int ts_password_creds_length = 0;
681
682         length = ber_skip_octet_string(credssp->ntlmssp->domain.length);
683         length += ber_skip_contextual_tag(length);
684         ts_password_creds_length += length;
685
686         length = ber_skip_octet_string(credssp->ntlmssp->username.length);
687         length += ber_skip_contextual_tag(length);
688         ts_password_creds_length += length;
689
690         length = ber_skip_octet_string(credssp->ntlmssp->password.length);
691         length += ber_skip_contextual_tag(length);
692         ts_password_creds_length += length;
693
694         length = ber_skip_sequence(ts_password_creds_length);
695
696         return length;
697 }
698
699 void credssp_write_ts_password_creds(rdpCredssp* credssp, STREAM* s)
700 {
701         int length;
702
703         length = credssp_skip_ts_password_creds(credssp);
704
705         /* TSPasswordCreds (SEQUENCE) */
706         length = ber_get_content_length(length);
707         ber_write_sequence_tag(s, length);
708
709         /* [0] domainName (OCTET STRING) */
710         ber_write_contextual_tag(s, 0, credssp->ntlmssp->domain.length + 2, true);
711         ber_write_octet_string(s, credssp->ntlmssp->domain.data, credssp->ntlmssp->domain.length);
712
713         /* [1] userName (OCTET STRING) */
714         ber_write_contextual_tag(s, 1, credssp->ntlmssp->username.length + 2, true);
715         ber_write_octet_string(s, credssp->ntlmssp->username.data, credssp->ntlmssp->username.length);
716
717         /* [2] password (OCTET STRING) */
718         ber_write_contextual_tag(s, 2, credssp->ntlmssp->password.length + 2, true);
719         ber_write_octet_string(s, credssp->ntlmssp->password.data, credssp->ntlmssp->password.length);
720 }
721
722 int credssp_skip_ts_credentials(rdpCredssp* credssp)
723 {
724         int length;
725         int ts_password_creds_length;
726         int ts_credentials_length = 0;
727
728         length = ber_skip_integer(0);
729         length += ber_skip_contextual_tag(length);
730         ts_credentials_length += length;
731
732         ts_password_creds_length = credssp_skip_ts_password_creds(credssp);
733         length = ber_skip_octet_string(ts_password_creds_length);
734         length += ber_skip_contextual_tag(length);
735         ts_credentials_length += length;
736
737         length = ber_skip_sequence(ts_credentials_length);
738
739         return length;
740 }
741
742 void credssp_write_ts_credentials(rdpCredssp* credssp, STREAM* s)
743 {
744         int length;
745         int ts_password_creds_length;
746
747         length = credssp_skip_ts_credentials(credssp);
748         ts_password_creds_length = credssp_skip_ts_password_creds(credssp);
749
750         /* TSCredentials (SEQUENCE) */
751         length = ber_get_content_length(length);
752         length -= ber_write_sequence_tag(s, length);
753
754         /* [0] credType (INTEGER) */
755         length -= ber_write_contextual_tag(s, 0, 3, true);
756         length -= ber_write_integer(s, 1);
757
758         /* [1] credentials (OCTET STRING) */
759         length -= 1;
760         length -= ber_write_contextual_tag(s, 1, length, true);
761         length -= ber_write_octet_string_tag(s, ts_password_creds_length);
762
763         credssp_write_ts_password_creds(credssp, s);
764 }
765
766 /**
767  * Encode TSCredentials structure.
768  * @param credssp
769  */
770
771 void credssp_encode_ts_credentials(rdpCredssp* credssp)
772 {
773         STREAM* s;
774         int length;
775
776         s = stream_new(0);
777         length = credssp_skip_ts_credentials(credssp);
778         freerdp_blob_alloc(&credssp->ts_credentials, length);
779         stream_attach(s, credssp->ts_credentials.data, length);
780
781         credssp_write_ts_credentials(credssp, s);
782         stream_detach(s);
783         stream_free(s);
784 }
785
786 int credssp_skip_nego_token(int length)
787 {
788         length = ber_skip_octet_string(length);
789         length += ber_skip_contextual_tag(length);
790         return length;
791 }
792
793 int credssp_skip_nego_tokens(int length)
794 {
795         length = credssp_skip_nego_token(length);
796         length += ber_skip_sequence_tag(length);
797         length += ber_skip_sequence_tag(length);
798         length += ber_skip_contextual_tag(length);
799         return length;
800 }
801
802 int credssp_skip_pub_key_auth(int length)
803 {
804         length = ber_skip_octet_string(length);
805         length += ber_skip_contextual_tag(length);
806         return length;
807 }
808
809 int credssp_skip_auth_info(int length)
810 {
811         length = ber_skip_octet_string(length);
812         length += ber_skip_contextual_tag(length);
813         return length;
814 }
815
816 int credssp_skip_ts_request(int length)
817 {
818         length += ber_skip_integer(2);
819         length += ber_skip_contextual_tag(3);
820         length += ber_skip_sequence_tag(length);
821         return length;
822 }
823
824 /**
825  * Send CredSSP message.
826  * @param credssp
827  * @param negoToken
828  * @param authInfo
829  * @param pubKeyAuth
830  */
831
832 void credssp_send(rdpCredssp* credssp, rdpBlob* negoToken, rdpBlob* authInfo, rdpBlob* pubKeyAuth)
833 {
834         STREAM* s;
835         int length;
836         int ts_request_length;
837         int nego_tokens_length;
838         int pub_key_auth_length;
839         int auth_info_length;
840
841         nego_tokens_length = (negoToken != NULL) ? credssp_skip_nego_tokens(negoToken->length) : 0;
842         pub_key_auth_length = (pubKeyAuth != NULL) ? credssp_skip_pub_key_auth(pubKeyAuth->length) : 0;
843         auth_info_length = (authInfo != NULL) ? credssp_skip_auth_info(authInfo->length) : 0;
844
845         length = nego_tokens_length + pub_key_auth_length + auth_info_length;
846         ts_request_length = credssp_skip_ts_request(length);
847
848         s = stream_new(ts_request_length);
849
850         /* TSRequest */
851         length = ber_get_content_length(ts_request_length);
852         ber_write_sequence_tag(s, length); /* SEQUENCE */
853         ber_write_contextual_tag(s, 0, 3, true); /* [0] version */
854         ber_write_integer(s, 2); /* INTEGER */
855
856         /* [1] negoTokens (NegoData) */
857         if (nego_tokens_length > 0)
858         {
859                 length = ber_get_content_length(nego_tokens_length);
860                 length -= ber_write_contextual_tag(s, 1, length, true); /* NegoData */
861                 length -= ber_write_sequence_tag(s, length); /* SEQUENCE OF NegoDataItem */
862                 length -= ber_write_sequence_tag(s, length); /* NegoDataItem */
863                 length -= ber_write_contextual_tag(s, 0, length, true); /* [0] negoToken */
864                 ber_write_octet_string(s, negoToken->data, length); /* OCTET STRING */
865         }
866
867         /* [2] authInfo (OCTET STRING) */
868         if (auth_info_length > 0)
869         {
870                 length = ber_get_content_length(auth_info_length);
871                 length -= ber_write_contextual_tag(s, 2, length, true);
872                 ber_write_octet_string(s, authInfo->data, authInfo->length);
873         }
874
875         /* [3] pubKeyAuth (OCTET STRING) */
876         if (pub_key_auth_length > 0)
877         {
878                 length = ber_get_content_length(pub_key_auth_length);
879                 length -= ber_write_contextual_tag(s, 3, length, true);
880                 ber_write_octet_string(s, pubKeyAuth->data, length);
881         }
882
883         tls_write(credssp->tls, s->data, stream_get_length(s));
884         stream_free(s);
885 }
886
887 /**
888  * Receive CredSSP message.
889  * @param credssp
890  * @param negoToken
891  * @param authInfo
892  * @param pubKeyAuth
893  * @return
894  */
895
896 int credssp_recv(rdpCredssp* credssp, rdpBlob* negoToken, rdpBlob* authInfo, rdpBlob* pubKeyAuth)
897 {
898         STREAM* s;
899         int length;
900         int status;
901         uint32 version;
902
903         s = stream_new(2048);
904         status = tls_read(credssp->tls, s->data, stream_get_left(s));
905
906         if (status < 0)
907                 return -1;
908
909         /* TSRequest */
910         ber_read_sequence_tag(s, &length);
911         ber_read_contextual_tag(s, 0, &length, true);
912         ber_read_integer(s, &version);
913
914         /* [1] negoTokens (NegoData) */
915         if (ber_read_contextual_tag(s, 1, &length, true) != false)
916         {
917                 ber_read_sequence_tag(s, &length); /* SEQUENCE OF NegoDataItem */
918                 ber_read_sequence_tag(s, &length); /* NegoDataItem */
919                 ber_read_contextual_tag(s, 0, &length, true); /* [0] negoToken */
920                 ber_read_octet_string(s, &length); /* OCTET STRING */
921                 freerdp_blob_alloc(negoToken, length);
922                 stream_read(s, negoToken->data, length);
923         }
924
925         /* [2] authInfo (OCTET STRING) */
926         if (ber_read_contextual_tag(s, 2, &length, true) != false)
927         {
928                 ber_read_octet_string(s, &length); /* OCTET STRING */
929                 freerdp_blob_alloc(authInfo, length);
930                 stream_read(s, authInfo->data, length);
931         }
932
933         /* [3] pubKeyAuth (OCTET STRING) */
934         if (ber_read_contextual_tag(s, 3, &length, true) != false)
935         {
936                 ber_read_octet_string(s, &length); /* OCTET STRING */
937                 freerdp_blob_alloc(pubKeyAuth, length);
938                 stream_read(s, pubKeyAuth->data, length);
939         }
940
941         return 0;
942 }
943
944 /**
945  * Encrypt the given plain text using RC4 and the given key.
946  * @param key RC4 key
947  * @param length text length
948  * @param plaintext plain text
949  * @param ciphertext cipher text
950  */
951
952 void credssp_rc4k(uint8* key, int length, uint8* plaintext, uint8* ciphertext)
953 {
954         CryptoRc4 rc4;
955
956         /* Initialize RC4 cipher with key */
957         rc4 = crypto_rc4_init((void*) key, 16);
958
959         /* Encrypt plaintext with key */
960         crypto_rc4(rc4, length, (void*) plaintext, (void*) ciphertext);
961
962         /* Free RC4 Cipher */
963         crypto_rc4_free(rc4);
964 }
965
966 /**
967  * Get current time, in tenths of microseconds since midnight of January 1, 1601.
968  * @param[out] timestamp 64-bit little-endian timestamp
969  */
970
971 void credssp_current_time(uint8* timestamp)
972 {
973         uint64 time64;
974
975         /* Timestamp (8 bytes), represented as the number of tenths of microseconds since midnight of January 1, 1601 */
976         time64 = time(NULL) + 11644473600LL; /* Seconds since January 1, 1601 */
977         time64 *= 10000000; /* Convert timestamp to tenths of a microsecond */
978
979         memcpy(timestamp, &time64, 8); /* Copy into timestamp in little-endian */
980 }
981
982 /**
983  * Create new CredSSP state machine.
984  * @param transport
985  * @return new CredSSP state machine.
986  */
987
988 rdpCredssp* credssp_new(freerdp* instance, rdpTls* tls, rdpSettings* settings)
989 {
990         rdpCredssp* credssp;
991
992         credssp = (rdpCredssp*) xzalloc(sizeof(rdpCredssp));
993
994         if (credssp != NULL)
995         {
996                 credssp->instance = instance;
997                 credssp->settings = settings;
998                 credssp->server = settings->server_mode;
999                 credssp->tls = tls;
1000
1001                 credssp->send_seq_num = 0;
1002
1003                 if (credssp->server)
1004                         credssp->ntlmssp = ntlmssp_server_new();
1005                 else
1006                         credssp->ntlmssp = ntlmssp_client_new();
1007         }
1008
1009         return credssp;
1010 }
1011
1012 /**
1013  * Free CredSSP state machine.
1014  * @param credssp
1015  */
1016
1017 void credssp_free(rdpCredssp* credssp)
1018 {
1019         if (credssp != NULL)
1020         {
1021                 freerdp_blob_free(&credssp->ts_credentials);
1022
1023                 ntlmssp_free(credssp->ntlmssp);
1024                 xfree(credssp);
1025         }
1026 }
1027
1028 /* SSPI */
1029
1030 const SECURITY_FUNCTION_TABLE CREDSSP_SECURITY_FUNCTION_TABLE =
1031 {
1032         1, /* dwVersion */
1033         NULL, /* EnumerateSecurityPackages */
1034         NULL, /* Reserved1 */
1035         NULL, /* QueryCredentialsAttributes */
1036         NULL, /* AcquireCredentialsHandle */
1037         NULL, /* FreeCredentialsHandle */
1038         NULL, /* Reserved2 */
1039         NULL, /* InitializeSecurityContext */
1040         NULL, /* AcceptSecurityContext */
1041         NULL, /* CompleteAuthToken */
1042         NULL, /* DeleteSecurityContext */
1043         NULL, /* ApplyControlToken */
1044         NULL, /* QueryContextAttributes */
1045         NULL, /* ImpersonateSecurityContext */
1046         NULL, /* RevertSecurityContext */
1047         NULL, /* MakeSignature */
1048         NULL, /* VerifySignature */
1049         NULL, /* FreeContextBuffer */
1050         NULL, /* QuerySecurityPackageInfo */
1051         NULL, /* Reserved3 */
1052         NULL, /* Reserved4 */
1053         NULL, /* ExportSecurityContext */
1054         NULL, /* ImportSecurityContext */
1055         NULL, /* AddCredentials */
1056         NULL, /* Reserved8 */
1057         NULL, /* QuerySecurityContextToken */
1058         NULL, /* EncryptMessage */
1059         NULL, /* DecryptMessage */
1060         NULL, /* SetContextAttributes */
1061 };
1062
1063 const SEC_PKG_INFO CREDSSP_SEC_PKG_INFO =
1064 {
1065         0x000110733, /* fCapabilities */
1066         1, /* wVersion */
1067         0xFFFF, /* wRPCID */
1068         0x000090A8, /* cbMaxToken */
1069         "CREDSSP", /* Name */
1070         "Microsoft CredSSP Security Provider" /* Comment */
1071 };