2 * FreeRDP: A Remote Desktop Protocol Implementation
3 * Credential Security Support Provider (CredSSP)
5 * Copyright 2010-2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
25 #include <freerdp/crypto/tls.h>
26 #include <freerdp/auth/ntlmssp.h>
27 #include <freerdp/utils/stream.h>
29 #include <freerdp/auth/sspi.h>
30 #include <freerdp/auth/credssp.h>
35 * TSRequest ::= SEQUENCE {
36 * version [0] INTEGER,
37 * negoTokens [1] NegoData OPTIONAL,
38 * authInfo [2] OCTET STRING OPTIONAL,
39 * pubKeyAuth [3] OCTET STRING OPTIONAL
42 * NegoData ::= SEQUENCE OF NegoDataItem
44 * NegoDataItem ::= SEQUENCE {
45 * negoToken [0] OCTET STRING
48 * TSCredentials ::= SEQUENCE {
49 * credType [0] INTEGER,
50 * credentials [1] OCTET STRING
53 * TSPasswordCreds ::= SEQUENCE {
54 * domainName [0] OCTET STRING,
55 * userName [1] OCTET STRING,
56 * password [2] OCTET STRING
59 * TSSmartCardCreds ::= SEQUENCE {
60 * pin [0] OCTET STRING,
61 * cspData [1] TSCspDataDetail,
62 * userHint [2] OCTET STRING OPTIONAL,
63 * domainHint [3] OCTET STRING OPTIONAL
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
77 * Initialize NTLMSSP authentication module (client).
81 int credssp_ntlmssp_client_init(rdpCredssp* credssp)
84 NTLMSSP* ntlmssp = credssp->ntlmssp;
85 rdpSettings* settings = credssp->settings;
86 instance = (freerdp*) settings->instance;
88 if ((settings->password == NULL) || (settings->username == NULL))
90 if (instance->Authenticate)
92 boolean proceed = instance->Authenticate(instance,
93 &settings->username, &settings->password, &settings->domain);
99 if (settings->ntlm_version == 2)
100 ntlmssp->ntlm_v2 = 1;
102 ntlmssp_set_password(ntlmssp, settings->password);
103 ntlmssp_set_username(ntlmssp, settings->username);
105 if (ntlmssp->ntlm_v2)
107 ntlmssp_set_workstation(ntlmssp, "WORKSTATION");
110 if (settings->domain != NULL)
112 if (strlen(settings->domain) > 0)
113 ntlmssp_set_domain(ntlmssp, settings->domain);
117 ntlmssp_set_domain(ntlmssp, NULL);
120 ntlmssp_generate_client_challenge(ntlmssp);
121 ntlmssp_generate_random_session_key(ntlmssp);
122 ntlmssp_generate_exported_session_key(ntlmssp);
128 * Initialize NTLMSSP authentication module (server).
132 int credssp_ntlmssp_server_init(rdpCredssp* credssp)
134 NTLMSSP* ntlmssp = credssp->ntlmssp;
136 ntlmssp_generate_server_challenge(ntlmssp);
142 * Authenticate with server using CredSSP (client).
144 * @return 1 if authentication is successful
149 int credssp_client_authenticate(rdpCredssp* credssp)
151 NTLMSSP* ntlmssp = credssp->ntlmssp;
152 STREAM* s = stream_new(0);
153 uint8* negoTokenBuffer = (uint8*) xmalloc(2048);
155 if (credssp_ntlmssp_client_init(credssp) == 0)
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);
165 /* NTLMSSP CHALLENGE MESSAGE */
166 if (credssp_recv(credssp, &credssp->negoToken, NULL, NULL) < 0)
169 stream_attach(s, credssp->negoToken.data, credssp->negoToken.length);
170 ntlmssp_recv(ntlmssp, s);
172 freerdp_blob_free(&credssp->negoToken);
174 /* NTLMSSP AUTHENTICATE MESSAGE */
175 stream_attach(s, negoTokenBuffer, 2048);
176 ntlmssp_send(ntlmssp, s);
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);
185 /* Encrypted Public Key +1 */
186 if (credssp_recv(credssp, &credssp->negoToken, NULL, &credssp->pubKeyAuth) < 0)
189 if (credssp_verify_public_key(credssp, &credssp->pubKeyAuth) == 0)
191 /* Failed to verify server public key echo */
192 return 0; /* DO NOT SEND CREDENTIALS! */
195 freerdp_blob_free(&credssp->negoToken);
196 freerdp_blob_free(&credssp->pubKeyAuth);
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);
211 #define NTLM_PACKAGE_NAME "NTLM"
213 int credssp_client_authenticate(rdpCredssp* credssp)
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;
237 if (credssp_ntlmssp_client_init(credssp) == 0)
240 table = InitSecurityInterface();
242 status = QuerySecurityPackageInfo(NTLM_PACKAGE_NAME, &pPackageInfo);
244 if (status != SEC_E_OK)
246 printf("QuerySecurityPackageInfo status: 0x%08X\n", status);
250 cbMaxLen = pPackageInfo->cbMaxToken;
252 identity.User = (uint16*) xstrdup(settings->username);
253 identity.UserLength = strlen(settings->username);
255 if (settings->domain)
257 identity.Domain = (uint16*) xstrdup(settings->domain);
258 identity.DomainLength = strlen(settings->domain);
262 identity.Domain = (uint16*) NULL;
263 identity.DomainLength = 0;
266 identity.Password = (uint16*) xstrdup(settings->password);
267 identity.PasswordLength = strlen(settings->password);
269 identity.Flags = SEC_AUTH_IDENTITY_ANSI;
271 status = table->AcquireCredentialsHandle(NULL, NTLM_PACKAGE_NAME,
272 SECPKG_CRED_OUTBOUND, NULL, &identity, NULL, NULL, &credentials, &expiration);
274 if (status != SEC_E_OK)
276 printf("AcquireCredentialsHandle status: 0x%08X\n", status);
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));
286 fContextReq = ISC_REQ_REPLAY_DETECT | ISC_REQ_SEQUENCE_DETECT |
287 ISC_REQ_CONFIDENTIALITY | ISC_REQ_DELEGATE;
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);
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);
304 if (input_sec_buffer.pvBuffer != NULL)
306 xfree(input_sec_buffer.pvBuffer);
307 input_sec_buffer.pvBuffer = NULL;
310 if ((status == SEC_I_COMPLETE_AND_CONTINUE) || (status == SEC_I_COMPLETE_NEEDED))
312 if (table->CompleteAuthToken != NULL)
313 table->CompleteAuthToken(&context, &output_sec_buffer_desc);
315 have_pub_key_auth = true;
317 if (have_pub_key_auth)
320 SEC_BUFFER Buffers[2];
321 SEC_BUFFER_DESC Message;
323 Buffers[0].BufferType = SECBUFFER_DATA; /* TLS Public Key */
324 Buffers[1].BufferType = SECBUFFER_PADDING; /* Signature */
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);
330 Buffers[1].cbBuffer = 16;
331 Buffers[1].pvBuffer = xzalloc(Buffers[1].cbBuffer);
333 Message.cBuffers = 2;
334 Message.ulVersion = SECBUFFER_VERSION;
335 Message.pBuffers = (SEC_BUFFER*) &Buffers;
337 freerdp_blob_alloc(&credssp->pubKeyAuth, Buffers[0].cbBuffer + Buffers[1].cbBuffer);
339 table->EncryptMessage(&context, 0, &Message, 0);
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 */
346 if (status == SEC_I_COMPLETE_NEEDED)
348 else if (status == SEC_I_COMPLETE_AND_CONTINUE)
349 status = SEC_I_CONTINUE_NEEDED;
352 /* send authentication token to server */
354 if (output_sec_buffer.cbBuffer > 0)
356 p_sec_buffer = &output_sec_buffer_desc.pBuffers[0];
358 credssp->negoToken.data = p_sec_buffer->pvBuffer;
359 credssp->negoToken.length = p_sec_buffer->cbBuffer;
361 printf("Sending Authentication Token\n");
362 freerdp_hexdump(credssp->negoToken.data, credssp->negoToken.length);
364 credssp_send(credssp, &credssp->negoToken, NULL,
365 (have_pub_key_auth) ? &credssp->pubKeyAuth : NULL);
367 if (have_pub_key_auth)
369 have_pub_key_auth = false;
370 freerdp_blob_free(&credssp->pubKeyAuth);
373 xfree(output_sec_buffer.pvBuffer);
374 output_sec_buffer.pvBuffer = NULL;
377 if (status != SEC_I_CONTINUE_NEEDED)
380 /* receive server response and place in input buffer */
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;
387 if (credssp_recv(credssp, &credssp->negoToken, NULL, NULL) < 0)
390 printf("Receiving Authentication Token\n");
391 freerdp_hexdump(credssp->negoToken.data, credssp->negoToken.length);
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;
397 have_input_buffer = true;
401 /* Encrypted Public Key +1 */
402 if (credssp_recv(credssp, &credssp->negoToken, NULL, &credssp->pubKeyAuth) < 0)
405 /* Verify Server Public Key Echo */
413 int public_key_length;
414 SEC_BUFFER Buffers[2];
415 SEC_BUFFER_DESC Message;
417 length = credssp->pubKeyAuth.length;
418 pub_key_auth = (uint8*) credssp->pubKeyAuth.data;
419 public_key_length = credssp->tls->public_key.length;
421 Buffers[0].BufferType = SECBUFFER_PADDING; /* Signature */
422 Buffers[1].BufferType = SECBUFFER_DATA; /* Encrypted TLS Public Key */
424 Buffers[0].cbBuffer = 16;
425 Buffers[0].pvBuffer = xmalloc(Buffers[0].cbBuffer);
426 memcpy(Buffers[0].pvBuffer, pub_key_auth, Buffers[0].cbBuffer);
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);
432 Message.cBuffers = 2;
433 Message.ulVersion = SECBUFFER_VERSION;
434 Message.pBuffers = (SEC_BUFFER*) &Buffers;
436 status = table->DecryptMessage(&context, &Message, 0, &pfQOP);
438 if (status != SEC_E_OK)
441 public_key1 = (uint8*) credssp->tls->public_key.data;
442 public_key2 = (uint8*) Buffers[1].pvBuffer;
444 public_key2[0]--; /* server echos the public key +1 */
446 if (memcmp(public_key1, public_key2, public_key_length) != 0)
448 printf("Could not verify server's public key echo\n");
450 printf("Expected (length = %d):\n", public_key_length);
451 freerdp_hexdump(public_key1, public_key_length);
453 printf("Actual (length = %d):\n", public_key_length);
454 freerdp_hexdump(public_key2, public_key_length);
456 return 0; /* DO NOT SEND CREDENTIALS! */
462 /* Send encrypted credentials */
463 credssp_encode_ts_credentials(credssp);
465 /* Encrypt TSCredentials */
469 SEC_BUFFER Buffers[2];
470 SEC_BUFFER_DESC Message;
472 Buffers[0].BufferType = SECBUFFER_DATA; /* TSCredentials */
473 Buffers[1].BufferType = SECBUFFER_PADDING; /* Signature */
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);
479 Buffers[1].cbBuffer = 16;
480 Buffers[1].pvBuffer = xzalloc(Buffers[1].cbBuffer);
482 Message.cBuffers = 2;
483 Message.ulVersion = SECBUFFER_VERSION;
484 Message.pBuffers = (SEC_BUFFER*) &Buffers;
486 freerdp_blob_alloc(&credssp->authInfo, Buffers[0].cbBuffer + Buffers[1].cbBuffer);
488 table->EncryptMessage(&context, 0, &Message, 1);
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 */
495 credssp_send(credssp, NULL, &credssp->authInfo, NULL);
497 freerdp_blob_free(&credssp->negoToken);
498 freerdp_blob_free(&credssp->pubKeyAuth);
499 freerdp_blob_free(&credssp->authInfo);
501 FreeCredentialsHandle(&credentials);
502 FreeContextBuffer(pPackageInfo);
510 * Authenticate with client using CredSSP (server).
512 * @return 1 if authentication is successful
515 int credssp_server_authenticate(rdpCredssp* credssp)
517 STREAM* s = stream_new(0);
518 NTLMSSP* ntlmssp = credssp->ntlmssp;
519 uint8* negoTokenBuffer = (uint8*) xmalloc(2048);
521 if (credssp_ntlmssp_server_init(credssp) == 0)
524 /* NTLMSSP NEGOTIATE MESSAGE */
525 if (credssp_recv(credssp, &credssp->negoToken, NULL, NULL) < 0)
528 stream_attach(s, credssp->negoToken.data, credssp->negoToken.length);
529 ntlmssp_recv(ntlmssp, s);
531 freerdp_blob_free(&credssp->negoToken);
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);
540 /* NTLMSSP AUTHENTICATE MESSAGE */
541 if (credssp_recv(credssp, &credssp->negoToken, NULL, &credssp->pubKeyAuth) < 0)
544 stream_attach(s, credssp->negoToken.data, credssp->negoToken.length);
545 ntlmssp_recv(ntlmssp, s);
551 * Authenticate using CredSSP.
553 * @return 1 if authentication is successful
556 int credssp_authenticate(rdpCredssp* credssp)
559 return credssp_server_authenticate(credssp);
561 return credssp_client_authenticate(credssp);
565 * Encrypt TLS public key using CredSSP.
570 void credssp_encrypt_public_key(rdpCredssp* credssp, rdpBlob* d)
575 rdpBlob encrypted_public_key;
576 NTLMSSP *ntlmssp = credssp->ntlmssp;
579 freerdp_blob_alloc(d, tls->public_key.length + 16);
580 ntlmssp_encrypt_message(ntlmssp, &tls->public_key, &encrypted_public_key, signature);
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);
587 printf("Encrypted Public Key (length = %d)\n", encrypted_public_key.length);
588 freerdp_hexdump(encrypted_public_key.data, encrypted_public_key.length);
591 printf("Signature\n");
592 freerdp_hexdump(signature, 16);
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 */
600 freerdp_blob_free(&encrypted_public_key);
604 * Verify TLS public key using CredSSP.
607 * @return 1 if verification is successful, 0 otherwise
610 int credssp_verify_public_key(rdpCredssp* credssp, rdpBlob* d)
615 rdpBlob encrypted_public_key;
616 rdpTls* tls = credssp->tls;
619 encrypted_public_key.data = (void*) (signature + 16);
620 encrypted_public_key.length = d->length - 16;
622 ntlmssp_decrypt_message(credssp->ntlmssp, &encrypted_public_key, &public_key, signature);
624 p1 = (uint8*) tls->public_key.data;
625 p2 = (uint8*) public_key.data;
629 if (memcmp(p1, p2, public_key.length) != 0)
631 printf("Could not verify server's public key echo\n");
636 freerdp_blob_free(&public_key);
641 * Encrypt and sign TSCredentials structure.
646 void credssp_encrypt_ts_credentials(rdpCredssp* credssp, rdpBlob* d)
650 rdpBlob encrypted_ts_credentials;
651 NTLMSSP* ntlmssp = credssp->ntlmssp;
653 freerdp_blob_alloc(d, credssp->ts_credentials.length + 16);
654 ntlmssp_encrypt_message(ntlmssp, &credssp->ts_credentials, &encrypted_ts_credentials, signature);
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);
661 printf("Encrypted TSCredentials (length = %d)\n", encrypted_ts_credentials.length);
662 freerdp_hexdump(encrypted_ts_credentials.data, encrypted_ts_credentials.length);
665 printf("Signature\n");
666 freerdp_hexdump(signature, 16);
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 */
674 freerdp_blob_free(&encrypted_ts_credentials);
677 int credssp_skip_ts_password_creds(rdpCredssp* credssp)
680 int ts_password_creds_length = 0;
682 length = ber_skip_octet_string(credssp->ntlmssp->domain.length);
683 length += ber_skip_contextual_tag(length);
684 ts_password_creds_length += length;
686 length = ber_skip_octet_string(credssp->ntlmssp->username.length);
687 length += ber_skip_contextual_tag(length);
688 ts_password_creds_length += length;
690 length = ber_skip_octet_string(credssp->ntlmssp->password.length);
691 length += ber_skip_contextual_tag(length);
692 ts_password_creds_length += length;
694 length = ber_skip_sequence(ts_password_creds_length);
699 void credssp_write_ts_password_creds(rdpCredssp* credssp, STREAM* s)
703 length = credssp_skip_ts_password_creds(credssp);
705 /* TSPasswordCreds (SEQUENCE) */
706 length = ber_get_content_length(length);
707 ber_write_sequence_tag(s, length);
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);
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);
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);
722 int credssp_skip_ts_credentials(rdpCredssp* credssp)
725 int ts_password_creds_length;
726 int ts_credentials_length = 0;
728 length = ber_skip_integer(0);
729 length += ber_skip_contextual_tag(length);
730 ts_credentials_length += length;
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;
737 length = ber_skip_sequence(ts_credentials_length);
742 void credssp_write_ts_credentials(rdpCredssp* credssp, STREAM* s)
745 int ts_password_creds_length;
747 length = credssp_skip_ts_credentials(credssp);
748 ts_password_creds_length = credssp_skip_ts_password_creds(credssp);
750 /* TSCredentials (SEQUENCE) */
751 length = ber_get_content_length(length);
752 length -= ber_write_sequence_tag(s, length);
754 /* [0] credType (INTEGER) */
755 length -= ber_write_contextual_tag(s, 0, 3, true);
756 length -= ber_write_integer(s, 1);
758 /* [1] credentials (OCTET STRING) */
760 length -= ber_write_contextual_tag(s, 1, length, true);
761 length -= ber_write_octet_string_tag(s, ts_password_creds_length);
763 credssp_write_ts_password_creds(credssp, s);
767 * Encode TSCredentials structure.
771 void credssp_encode_ts_credentials(rdpCredssp* credssp)
777 length = credssp_skip_ts_credentials(credssp);
778 freerdp_blob_alloc(&credssp->ts_credentials, length);
779 stream_attach(s, credssp->ts_credentials.data, length);
781 credssp_write_ts_credentials(credssp, s);
786 int credssp_skip_nego_token(int length)
788 length = ber_skip_octet_string(length);
789 length += ber_skip_contextual_tag(length);
793 int credssp_skip_nego_tokens(int length)
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);
802 int credssp_skip_pub_key_auth(int length)
804 length = ber_skip_octet_string(length);
805 length += ber_skip_contextual_tag(length);
809 int credssp_skip_auth_info(int length)
811 length = ber_skip_octet_string(length);
812 length += ber_skip_contextual_tag(length);
816 int credssp_skip_ts_request(int length)
818 length += ber_skip_integer(2);
819 length += ber_skip_contextual_tag(3);
820 length += ber_skip_sequence_tag(length);
825 * Send CredSSP message.
832 void credssp_send(rdpCredssp* credssp, rdpBlob* negoToken, rdpBlob* authInfo, rdpBlob* pubKeyAuth)
836 int ts_request_length;
837 int nego_tokens_length;
838 int pub_key_auth_length;
839 int auth_info_length;
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;
845 length = nego_tokens_length + pub_key_auth_length + auth_info_length;
846 ts_request_length = credssp_skip_ts_request(length);
848 s = stream_new(ts_request_length);
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 */
856 /* [1] negoTokens (NegoData) */
857 if (nego_tokens_length > 0)
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 */
867 /* [2] authInfo (OCTET STRING) */
868 if (auth_info_length > 0)
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);
875 /* [3] pubKeyAuth (OCTET STRING) */
876 if (pub_key_auth_length > 0)
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);
883 tls_write(credssp->tls, s->data, stream_get_length(s));
888 * Receive CredSSP message.
896 int credssp_recv(rdpCredssp* credssp, rdpBlob* negoToken, rdpBlob* authInfo, rdpBlob* pubKeyAuth)
903 s = stream_new(2048);
904 status = tls_read(credssp->tls, s->data, stream_get_left(s));
910 ber_read_sequence_tag(s, &length);
911 ber_read_contextual_tag(s, 0, &length, true);
912 ber_read_integer(s, &version);
914 /* [1] negoTokens (NegoData) */
915 if (ber_read_contextual_tag(s, 1, &length, true) != false)
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);
925 /* [2] authInfo (OCTET STRING) */
926 if (ber_read_contextual_tag(s, 2, &length, true) != false)
928 ber_read_octet_string(s, &length); /* OCTET STRING */
929 freerdp_blob_alloc(authInfo, length);
930 stream_read(s, authInfo->data, length);
933 /* [3] pubKeyAuth (OCTET STRING) */
934 if (ber_read_contextual_tag(s, 3, &length, true) != false)
936 ber_read_octet_string(s, &length); /* OCTET STRING */
937 freerdp_blob_alloc(pubKeyAuth, length);
938 stream_read(s, pubKeyAuth->data, length);
945 * Encrypt the given plain text using RC4 and the given key.
947 * @param length text length
948 * @param plaintext plain text
949 * @param ciphertext cipher text
952 void credssp_rc4k(uint8* key, int length, uint8* plaintext, uint8* ciphertext)
956 /* Initialize RC4 cipher with key */
957 rc4 = crypto_rc4_init((void*) key, 16);
959 /* Encrypt plaintext with key */
960 crypto_rc4(rc4, length, (void*) plaintext, (void*) ciphertext);
962 /* Free RC4 Cipher */
963 crypto_rc4_free(rc4);
967 * Get current time, in tenths of microseconds since midnight of January 1, 1601.
968 * @param[out] timestamp 64-bit little-endian timestamp
971 void credssp_current_time(uint8* timestamp)
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 */
979 memcpy(timestamp, &time64, 8); /* Copy into timestamp in little-endian */
983 * Create new CredSSP state machine.
985 * @return new CredSSP state machine.
988 rdpCredssp* credssp_new(freerdp* instance, rdpTls* tls, rdpSettings* settings)
992 credssp = (rdpCredssp*) xzalloc(sizeof(rdpCredssp));
996 credssp->instance = instance;
997 credssp->settings = settings;
998 credssp->server = settings->server_mode;
1001 credssp->send_seq_num = 0;
1003 if (credssp->server)
1004 credssp->ntlmssp = ntlmssp_server_new();
1006 credssp->ntlmssp = ntlmssp_client_new();
1013 * Free CredSSP state machine.
1017 void credssp_free(rdpCredssp* credssp)
1019 if (credssp != NULL)
1021 freerdp_blob_free(&credssp->ts_credentials);
1023 ntlmssp_free(credssp->ntlmssp);
1030 const SECURITY_FUNCTION_TABLE CREDSSP_SECURITY_FUNCTION_TABLE =
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 */
1063 const SEC_PKG_INFO CREDSSP_SEC_PKG_INFO =
1065 0x000110733, /* fCapabilities */
1067 0xFFFF, /* wRPCID */
1068 0x000090A8, /* cbMaxToken */
1069 "CREDSSP", /* Name */
1070 "Microsoft CredSSP Security Provider" /* Comment */