2 * WinPR: Windows Portable Runtime
3 * Network Level Authentication (NLA)
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.
30 #include <freerdp/crypto/tls.h>
32 #include <winpr/crt.h>
33 #include <winpr/sspi.h>
34 #include <winpr/print.h>
35 #include <winpr/tchar.h>
36 #include <winpr/library.h>
37 #include <winpr/registry.h>
42 * TSRequest ::= SEQUENCE {
43 * version [0] INTEGER,
44 * negoTokens [1] NegoData OPTIONAL,
45 * authInfo [2] OCTET STRING OPTIONAL,
46 * pubKeyAuth [3] OCTET STRING OPTIONAL
49 * NegoData ::= SEQUENCE OF NegoDataItem
51 * NegoDataItem ::= SEQUENCE {
52 * negoToken [0] OCTET STRING
55 * TSCredentials ::= SEQUENCE {
56 * credType [0] INTEGER,
57 * credentials [1] OCTET STRING
60 * TSPasswordCreds ::= SEQUENCE {
61 * domainName [0] OCTET STRING,
62 * userName [1] OCTET STRING,
63 * password [2] OCTET STRING
66 * TSSmartCardCreds ::= SEQUENCE {
67 * pin [0] OCTET STRING,
68 * cspData [1] TSCspDataDetail,
69 * userHint [2] OCTET STRING OPTIONAL,
70 * domainHint [3] OCTET STRING OPTIONAL
73 * TSCspDataDetail ::= SEQUENCE {
74 * keySpec [0] INTEGER,
75 * cardName [1] OCTET STRING OPTIONAL,
76 * readerName [2] OCTET STRING OPTIONAL,
77 * containerName [3] OCTET STRING OPTIONAL,
78 * cspName [4] OCTET STRING OPTIONAL
84 #define WITH_DEBUG_CREDSSP
87 #ifdef WITH_NATIVE_SSPI
88 #define NLA_PKG_NAME NTLMSP_NAME
90 #define NLA_PKG_NAME NTLMSP_NAME
93 #define TERMSRV_SPN_PREFIX "TERMSRV/"
95 void credssp_send(rdpCredssp* credssp);
96 int credssp_recv(rdpCredssp* credssp);
97 void credssp_buffer_print(rdpCredssp* credssp);
98 void credssp_buffer_free(rdpCredssp* credssp);
99 SECURITY_STATUS credssp_encrypt_public_key_echo(rdpCredssp* credssp);
100 SECURITY_STATUS credssp_decrypt_public_key_echo(rdpCredssp* credssp);
101 SECURITY_STATUS credssp_encrypt_ts_credentials(rdpCredssp* credssp);
102 SECURITY_STATUS credssp_decrypt_ts_credentials(rdpCredssp* credssp);
104 #define ber_sizeof_sequence_octet_string(length) ber_sizeof_contextual_tag(ber_sizeof_octet_string(length)) + ber_sizeof_octet_string(length)
105 #define ber_write_sequence_octet_string(stream, context, value, length) ber_write_contextual_tag(stream, context, ber_sizeof_octet_string(length), TRUE) + ber_write_octet_string(stream, value, length)
108 * Initialize NTLMSSP authentication module (client).
112 int credssp_ntlm_client_init(rdpCredssp* credssp)
118 rdpSettings* settings;
120 settings = credssp->settings;
121 instance = (freerdp*) settings->instance;
123 if ((settings->Password == NULL ) || (settings->Username == NULL)
124 || (!strlen(settings->Password)) || (!strlen(settings->Username)))
126 if (instance->Authenticate)
128 BOOL proceed = instance->Authenticate(instance,
129 &settings->Username, &settings->Password, &settings->Domain);
135 sspi_SetAuthIdentity(&(credssp->identity), settings->Username, settings->Domain, settings->Password);
137 #ifdef WITH_DEBUG_NLA
138 _tprintf(_T("User: %s Domain: %s Password: %s\n"),
139 (char*) credssp->identity.User, (char*) credssp->identity.Domain, (char*) credssp->identity.Password);
142 if (credssp->transport->layer == TRANSPORT_LAYER_TLS)
144 tls = credssp->transport->TlsIn;
146 else if (credssp->transport->layer == TRANSPORT_LAYER_TSG_TLS)
148 tls = credssp->transport->TsgTls;
152 fprintf(stderr, "Unknown NLA transport layer\n");
156 sspi_SecBufferAlloc(&credssp->PublicKey, tls->PublicKeyLength);
157 CopyMemory(credssp->PublicKey.pvBuffer, tls->PublicKey, tls->PublicKeyLength);
159 length = sizeof(TERMSRV_SPN_PREFIX) + strlen(settings->ServerHostname);
161 spn = (SEC_CHAR*) malloc(length + 1);
162 sprintf(spn, "%s%s", TERMSRV_SPN_PREFIX, settings->ServerHostname);
165 credssp->ServicePrincipalName = (LPTSTR) malloc(length * 2 + 2);
166 MultiByteToWideChar(CP_UTF8, 0, spn, length,
167 (LPWSTR) credssp->ServicePrincipalName, length);
170 credssp->ServicePrincipalName = spn;
177 * Initialize NTLMSSP authentication module (server).
181 int credssp_ntlm_server_init(rdpCredssp* credssp)
184 rdpSettings* settings = credssp->settings;
185 instance = (freerdp*) settings->instance;
187 sspi_SecBufferAlloc(&credssp->PublicKey, credssp->transport->TlsIn->PublicKeyLength);
188 CopyMemory(credssp->PublicKey.pvBuffer, credssp->transport->TlsIn->PublicKey, credssp->transport->TlsIn->PublicKeyLength);
193 int credssp_client_authenticate(rdpCredssp* credssp)
198 SECURITY_STATUS status;
199 CredHandle credentials;
200 TimeStamp expiration;
201 PSecPkgInfo pPackageInfo;
202 SecBuffer input_buffer;
203 SecBuffer output_buffer;
204 SecBufferDesc input_buffer_desc;
205 SecBufferDesc output_buffer_desc;
207 BOOL have_input_buffer;
208 BOOL have_pub_key_auth;
212 if (credssp_ntlm_client_init(credssp) == 0)
215 #ifdef WITH_NATIVE_SSPI
218 INIT_SECURITY_INTERFACE InitSecurityInterface;
219 PSecurityFunctionTable pSecurityInterface = NULL;
221 hSSPI = LoadLibrary(_T("secur32.dll"));
224 InitSecurityInterface = (INIT_SECURITY_INTERFACE) GetProcAddress(hSSPI, "InitSecurityInterfaceW");
226 InitSecurityInterface = (INIT_SECURITY_INTERFACE) GetProcAddress(hSSPI, "InitSecurityInterfaceA");
228 credssp->table = (*InitSecurityInterface)();
231 credssp->table = InitSecurityInterface();
234 status = credssp->table->QuerySecurityPackageInfo(NLA_PKG_NAME, &pPackageInfo);
236 if (status != SEC_E_OK)
238 fprintf(stderr, "QuerySecurityPackageInfo status: 0x%08X\n", status);
242 cbMaxToken = pPackageInfo->cbMaxToken;
244 status = credssp->table->AcquireCredentialsHandle(NULL, NLA_PKG_NAME,
245 SECPKG_CRED_OUTBOUND, NULL, &credssp->identity, NULL, NULL, &credentials, &expiration);
247 if (status != SEC_E_OK)
249 fprintf(stderr, "AcquireCredentialsHandle status: 0x%08X\n", status);
253 have_context = FALSE;
254 have_input_buffer = FALSE;
255 have_pub_key_auth = FALSE;
256 ZeroMemory(&input_buffer, sizeof(SecBuffer));
257 ZeroMemory(&output_buffer, sizeof(SecBuffer));
258 ZeroMemory(&credssp->ContextSizes, sizeof(SecPkgContext_Sizes));
261 * from tspkg.dll: 0x00000132
262 * ISC_REQ_MUTUAL_AUTH
263 * ISC_REQ_CONFIDENTIALITY
264 * ISC_REQ_USE_SESSION_KEY
265 * ISC_REQ_ALLOCATE_MEMORY
268 fContextReq = ISC_REQ_MUTUAL_AUTH | ISC_REQ_CONFIDENTIALITY | ISC_REQ_USE_SESSION_KEY;
272 output_buffer_desc.ulVersion = SECBUFFER_VERSION;
273 output_buffer_desc.cBuffers = 1;
274 output_buffer_desc.pBuffers = &output_buffer;
275 output_buffer.BufferType = SECBUFFER_TOKEN;
276 output_buffer.cbBuffer = cbMaxToken;
277 output_buffer.pvBuffer = malloc(output_buffer.cbBuffer);
279 status = credssp->table->InitializeSecurityContext(&credentials,
280 (have_context) ? &credssp->context : NULL,
281 credssp->ServicePrincipalName, fContextReq, 0,
282 SECURITY_NATIVE_DREP, (have_input_buffer) ? &input_buffer_desc : NULL,
283 0, &credssp->context, &output_buffer_desc, &pfContextAttr, &expiration);
285 if (have_input_buffer && (input_buffer.pvBuffer != NULL))
287 free(input_buffer.pvBuffer);
288 input_buffer.pvBuffer = NULL;
291 if ((status == SEC_I_COMPLETE_AND_CONTINUE) || (status == SEC_I_COMPLETE_NEEDED) || (status == SEC_E_OK))
293 if (credssp->table->CompleteAuthToken != NULL)
294 credssp->table->CompleteAuthToken(&credssp->context, &output_buffer_desc);
296 have_pub_key_auth = TRUE;
298 if (credssp->table->QueryContextAttributes(&credssp->context, SECPKG_ATTR_SIZES, &credssp->ContextSizes) != SEC_E_OK)
300 fprintf(stderr, "QueryContextAttributes SECPKG_ATTR_SIZES failure\n");
304 credssp_encrypt_public_key_echo(credssp);
306 if (status == SEC_I_COMPLETE_NEEDED)
308 else if (status == SEC_I_COMPLETE_AND_CONTINUE)
309 status = SEC_I_CONTINUE_NEEDED;
312 /* send authentication token to server */
314 if (output_buffer.cbBuffer > 0)
316 credssp->negoToken.pvBuffer = output_buffer.pvBuffer;
317 credssp->negoToken.cbBuffer = output_buffer.cbBuffer;
319 #ifdef WITH_DEBUG_CREDSSP
320 fprintf(stderr, "Sending Authentication Token\n");
321 winpr_HexDump(credssp->negoToken.pvBuffer, credssp->negoToken.cbBuffer);
324 credssp_send(credssp);
325 credssp_buffer_free(credssp);
328 if (status != SEC_I_CONTINUE_NEEDED)
331 /* receive server response and place in input buffer */
333 input_buffer_desc.ulVersion = SECBUFFER_VERSION;
334 input_buffer_desc.cBuffers = 1;
335 input_buffer_desc.pBuffers = &input_buffer;
336 input_buffer.BufferType = SECBUFFER_TOKEN;
338 if (credssp_recv(credssp) < 0)
341 #ifdef WITH_DEBUG_CREDSSP
342 fprintf(stderr, "Receiving Authentication Token (%d)\n", (int) credssp->negoToken.cbBuffer);
343 winpr_HexDump(credssp->negoToken.pvBuffer, credssp->negoToken.cbBuffer);
346 input_buffer.pvBuffer = credssp->negoToken.pvBuffer;
347 input_buffer.cbBuffer = credssp->negoToken.cbBuffer;
349 have_input_buffer = TRUE;
353 /* Encrypted Public Key +1 */
354 if (credssp_recv(credssp) < 0)
357 /* Verify Server Public Key Echo */
359 status = credssp_decrypt_public_key_echo(credssp);
360 credssp_buffer_free(credssp);
362 if (status != SEC_E_OK)
364 fprintf(stderr, "Could not verify public key echo!\n");
368 /* Send encrypted credentials */
370 status = credssp_encrypt_ts_credentials(credssp);
372 if (status != SEC_E_OK)
374 fprintf(stderr, "credssp_encrypt_ts_credentials status: 0x%08X\n", status);
378 credssp_send(credssp);
379 credssp_buffer_free(credssp);
383 credssp->table->FreeCredentialsHandle(&credentials);
384 credssp->table->FreeContextBuffer(pPackageInfo);
390 * Authenticate with client using CredSSP (server).
392 * @return 1 if authentication is successful
395 int credssp_server_authenticate(rdpCredssp* credssp)
400 SECURITY_STATUS status;
401 CredHandle credentials;
402 TimeStamp expiration;
403 PSecPkgInfo pPackageInfo;
404 SecBuffer input_buffer;
405 SecBuffer output_buffer;
406 SecBufferDesc input_buffer_desc;
407 SecBufferDesc output_buffer_desc;
409 BOOL have_input_buffer;
410 BOOL have_pub_key_auth;
414 if (credssp_ntlm_server_init(credssp) == 0)
417 #ifdef WITH_NATIVE_SSPI
418 if (!credssp->SspiModule)
419 credssp->SspiModule = _tcsdup(_T("secur32.dll"));
422 if (credssp->SspiModule)
425 INIT_SECURITY_INTERFACE pInitSecurityInterface;
427 hSSPI = LoadLibrary(credssp->SspiModule);
431 _tprintf(_T("Failed to load SSPI module: %s\n"), credssp->SspiModule);
436 pInitSecurityInterface = (INIT_SECURITY_INTERFACE) GetProcAddress(hSSPI, "InitSecurityInterfaceW");
438 pInitSecurityInterface = (INIT_SECURITY_INTERFACE) GetProcAddress(hSSPI, "InitSecurityInterfaceA");
441 credssp->table = (*pInitSecurityInterface)();
443 #ifndef WITH_NATIVE_SSPI
446 credssp->table = InitSecurityInterface();
450 status = credssp->table->QuerySecurityPackageInfo(NLA_PKG_NAME, &pPackageInfo);
452 if (status != SEC_E_OK)
454 fprintf(stderr, "QuerySecurityPackageInfo status: 0x%08X\n", status);
458 cbMaxToken = pPackageInfo->cbMaxToken;
460 status = credssp->table->AcquireCredentialsHandle(NULL, NLA_PKG_NAME,
461 SECPKG_CRED_INBOUND, NULL, NULL, NULL, NULL, &credentials, &expiration);
463 if (status != SEC_E_OK)
465 fprintf(stderr, "AcquireCredentialsHandle status: 0x%08X\n", status);
469 have_context = FALSE;
470 have_input_buffer = FALSE;
471 have_pub_key_auth = FALSE;
472 ZeroMemory(&input_buffer, sizeof(SecBuffer));
473 ZeroMemory(&output_buffer, sizeof(SecBuffer));
474 ZeroMemory(&input_buffer_desc, sizeof(SecBufferDesc));
475 ZeroMemory(&output_buffer_desc, sizeof(SecBufferDesc));
476 ZeroMemory(&credssp->ContextSizes, sizeof(SecPkgContext_Sizes));
479 * from tspkg.dll: 0x00000112
480 * ASC_REQ_MUTUAL_AUTH
481 * ASC_REQ_CONFIDENTIALITY
482 * ASC_REQ_ALLOCATE_MEMORY
486 fContextReq |= ASC_REQ_MUTUAL_AUTH;
487 fContextReq |= ASC_REQ_CONFIDENTIALITY;
489 fContextReq |= ASC_REQ_CONNECTION;
490 fContextReq |= ASC_REQ_USE_SESSION_KEY;
492 fContextReq |= ASC_REQ_REPLAY_DETECT;
493 fContextReq |= ASC_REQ_SEQUENCE_DETECT;
495 fContextReq |= ASC_REQ_EXTENDED_ERROR;
499 input_buffer_desc.ulVersion = SECBUFFER_VERSION;
500 input_buffer_desc.cBuffers = 1;
501 input_buffer_desc.pBuffers = &input_buffer;
502 input_buffer.BufferType = SECBUFFER_TOKEN;
504 /* receive authentication token */
506 input_buffer_desc.ulVersion = SECBUFFER_VERSION;
507 input_buffer_desc.cBuffers = 1;
508 input_buffer_desc.pBuffers = &input_buffer;
509 input_buffer.BufferType = SECBUFFER_TOKEN;
511 if (credssp_recv(credssp) < 0)
514 #ifdef WITH_DEBUG_CREDSSP
515 fprintf(stderr, "Receiving Authentication Token\n");
516 credssp_buffer_print(credssp);
519 input_buffer.pvBuffer = credssp->negoToken.pvBuffer;
520 input_buffer.cbBuffer = credssp->negoToken.cbBuffer;
522 if (credssp->negoToken.cbBuffer < 1)
524 fprintf(stderr, "CredSSP: invalid negoToken!\n");
528 output_buffer_desc.ulVersion = SECBUFFER_VERSION;
529 output_buffer_desc.cBuffers = 1;
530 output_buffer_desc.pBuffers = &output_buffer;
531 output_buffer.BufferType = SECBUFFER_TOKEN;
532 output_buffer.cbBuffer = cbMaxToken;
533 output_buffer.pvBuffer = malloc(output_buffer.cbBuffer);
535 status = credssp->table->AcceptSecurityContext(&credentials,
536 have_context? &credssp->context: NULL,
537 &input_buffer_desc, fContextReq, SECURITY_NATIVE_DREP, &credssp->context,
538 &output_buffer_desc, &pfContextAttr, &expiration);
540 credssp->negoToken.pvBuffer = output_buffer.pvBuffer;
541 credssp->negoToken.cbBuffer = output_buffer.cbBuffer;
543 if ((status == SEC_I_COMPLETE_AND_CONTINUE) || (status == SEC_I_COMPLETE_NEEDED))
545 if (credssp->table->CompleteAuthToken != NULL)
546 credssp->table->CompleteAuthToken(&credssp->context, &output_buffer_desc);
548 if (status == SEC_I_COMPLETE_NEEDED)
550 else if (status == SEC_I_COMPLETE_AND_CONTINUE)
551 status = SEC_I_CONTINUE_NEEDED;
554 if (status == SEC_E_OK)
556 have_pub_key_auth = TRUE;
558 if (credssp->table->QueryContextAttributes(&credssp->context, SECPKG_ATTR_SIZES, &credssp->ContextSizes) != SEC_E_OK)
560 fprintf(stderr, "QueryContextAttributes SECPKG_ATTR_SIZES failure\n");
564 if (credssp_decrypt_public_key_echo(credssp) != SEC_E_OK)
566 fprintf(stderr, "Error: could not verify client's public key echo\n");
570 sspi_SecBufferFree(&credssp->negoToken);
571 credssp->negoToken.pvBuffer = NULL;
572 credssp->negoToken.cbBuffer = 0;
574 credssp_encrypt_public_key_echo(credssp);
577 if ((status != SEC_E_OK) && (status != SEC_I_CONTINUE_NEEDED))
579 fprintf(stderr, "AcceptSecurityContext status: 0x%08X\n", status);
583 /* send authentication token */
585 #ifdef WITH_DEBUG_CREDSSP
586 fprintf(stderr, "Sending Authentication Token\n");
587 credssp_buffer_print(credssp);
590 credssp_send(credssp);
591 credssp_buffer_free(credssp);
593 if (status != SEC_I_CONTINUE_NEEDED)
599 /* Receive encrypted credentials */
601 if (credssp_recv(credssp) < 0)
604 if (credssp_decrypt_ts_credentials(credssp) != SEC_E_OK)
606 fprintf(stderr, "Could not decrypt TSCredentials status: 0x%08X\n", status);
610 if (status != SEC_E_OK)
612 fprintf(stderr, "AcceptSecurityContext status: 0x%08X\n", status);
616 status = credssp->table->ImpersonateSecurityContext(&credssp->context);
618 if (status != SEC_E_OK)
620 fprintf(stderr, "ImpersonateSecurityContext status: 0x%08X\n", status);
625 status = credssp->table->RevertSecurityContext(&credssp->context);
627 if (status != SEC_E_OK)
629 fprintf(stderr, "RevertSecurityContext status: 0x%08X\n", status);
634 credssp->table->FreeContextBuffer(pPackageInfo);
640 * Authenticate using CredSSP.
642 * @return 1 if authentication is successful
645 int credssp_authenticate(rdpCredssp* credssp)
648 return credssp_server_authenticate(credssp);
650 return credssp_client_authenticate(credssp);
653 void ap_integer_increment_le(BYTE* number, int size)
657 for (index = 0; index < size; index++)
659 if (number[index] < 0xFF)
672 void ap_integer_decrement_le(BYTE* number, int size)
676 for (index = 0; index < size; index++)
678 if (number[index] > 0)
685 number[index] = 0xFF;
691 SECURITY_STATUS credssp_encrypt_public_key_echo(rdpCredssp* credssp)
693 SecBuffer Buffers[2];
694 SecBufferDesc Message;
695 SECURITY_STATUS status;
696 int public_key_length;
698 public_key_length = credssp->PublicKey.cbBuffer;
700 Buffers[0].BufferType = SECBUFFER_TOKEN; /* Signature */
701 Buffers[1].BufferType = SECBUFFER_DATA; /* TLS Public Key */
703 sspi_SecBufferAlloc(&credssp->pubKeyAuth, credssp->ContextSizes.cbMaxSignature + public_key_length);
705 Buffers[0].cbBuffer = credssp->ContextSizes.cbMaxSignature;
706 Buffers[0].pvBuffer = credssp->pubKeyAuth.pvBuffer;
708 Buffers[1].cbBuffer = public_key_length;
709 Buffers[1].pvBuffer = ((BYTE*) credssp->pubKeyAuth.pvBuffer) + credssp->ContextSizes.cbMaxSignature;
710 CopyMemory(Buffers[1].pvBuffer, credssp->PublicKey.pvBuffer, Buffers[1].cbBuffer);
714 /* server echos the public key +1 */
715 ap_integer_increment_le((BYTE*) Buffers[1].pvBuffer, Buffers[1].cbBuffer);
718 Message.cBuffers = 2;
719 Message.ulVersion = SECBUFFER_VERSION;
720 Message.pBuffers = (PSecBuffer) &Buffers;
722 status = credssp->table->EncryptMessage(&credssp->context, 0, &Message, credssp->send_seq_num++);
724 if (status != SEC_E_OK)
726 fprintf(stderr, "EncryptMessage status: 0x%08X\n", status);
733 SECURITY_STATUS credssp_decrypt_public_key_echo(rdpCredssp* credssp)
740 int public_key_length;
741 SecBuffer Buffers[2];
742 SecBufferDesc Message;
743 SECURITY_STATUS status;
745 if (credssp->PublicKey.cbBuffer + credssp->ContextSizes.cbMaxSignature != credssp->pubKeyAuth.cbBuffer)
747 fprintf(stderr, "unexpected pubKeyAuth buffer size:%d\n", (int) credssp->pubKeyAuth.cbBuffer);
748 return SEC_E_INVALID_TOKEN;
751 length = credssp->pubKeyAuth.cbBuffer;
752 buffer = (BYTE*) malloc(length);
753 CopyMemory(buffer, credssp->pubKeyAuth.pvBuffer, length);
755 public_key_length = credssp->PublicKey.cbBuffer;
757 Buffers[0].BufferType = SECBUFFER_TOKEN; /* Signature */
758 Buffers[1].BufferType = SECBUFFER_DATA; /* Encrypted TLS Public Key */
760 Buffers[0].cbBuffer = credssp->ContextSizes.cbMaxSignature;
761 Buffers[0].pvBuffer = buffer;
763 Buffers[1].cbBuffer = length - credssp->ContextSizes.cbMaxSignature;
764 Buffers[1].pvBuffer = buffer + credssp->ContextSizes.cbMaxSignature;
766 Message.cBuffers = 2;
767 Message.ulVersion = SECBUFFER_VERSION;
768 Message.pBuffers = (PSecBuffer) &Buffers;
770 status = credssp->table->DecryptMessage(&credssp->context, &Message, credssp->recv_seq_num++, &pfQOP);
772 if (status != SEC_E_OK)
774 fprintf(stderr, "DecryptMessage failure: 0x%08X\n", status);
778 public_key1 = (BYTE*) credssp->PublicKey.pvBuffer;
779 public_key2 = (BYTE*) Buffers[1].pvBuffer;
781 if (!credssp->server)
783 /* server echos the public key +1 */
784 ap_integer_decrement_le(public_key2, public_key_length);
787 if (memcmp(public_key1, public_key2, public_key_length) != 0)
789 fprintf(stderr, "Could not verify server's public key echo\n");
791 fprintf(stderr, "Expected (length = %d):\n", public_key_length);
792 winpr_HexDump(public_key1, public_key_length);
794 fprintf(stderr, "Actual (length = %d):\n", public_key_length);
795 winpr_HexDump(public_key2, public_key_length);
797 return SEC_E_MESSAGE_ALTERED; /* DO NOT SEND CREDENTIALS! */
805 int credssp_sizeof_ts_password_creds(rdpCredssp* credssp)
809 length += ber_sizeof_sequence_octet_string(credssp->identity.DomainLength * 2);
810 length += ber_sizeof_sequence_octet_string(credssp->identity.UserLength * 2);
811 length += ber_sizeof_sequence_octet_string(credssp->identity.PasswordLength * 2);
816 void credssp_read_ts_password_creds(rdpCredssp* credssp, wStream* s)
820 /* TSPasswordCreds (SEQUENCE) */
821 ber_read_sequence_tag(s, &length);
823 /* [0] domainName (OCTET STRING) */
824 ber_read_contextual_tag(s, 0, &length, TRUE);
825 ber_read_octet_string_tag(s, &length);
826 credssp->identity.DomainLength = (UINT32) length;
827 credssp->identity.Domain = (UINT16*) malloc(length);
828 CopyMemory(credssp->identity.Domain, Stream_Pointer(s), credssp->identity.DomainLength);
829 Stream_Seek(s, credssp->identity.DomainLength);
830 credssp->identity.DomainLength /= 2;
832 /* [1] userName (OCTET STRING) */
833 ber_read_contextual_tag(s, 1, &length, TRUE);
834 ber_read_octet_string_tag(s, &length);
835 credssp->identity.UserLength = (UINT32) length;
836 credssp->identity.User = (UINT16*) malloc(length);
837 CopyMemory(credssp->identity.User, Stream_Pointer(s), credssp->identity.UserLength);
838 Stream_Seek(s, credssp->identity.UserLength);
839 credssp->identity.UserLength /= 2;
841 /* [2] password (OCTET STRING) */
842 ber_read_contextual_tag(s, 2, &length, TRUE);
843 ber_read_octet_string_tag(s, &length);
844 credssp->identity.PasswordLength = (UINT32) length;
845 credssp->identity.Password = (UINT16*) malloc(length);
846 CopyMemory(credssp->identity.Password, Stream_Pointer(s), credssp->identity.PasswordLength);
847 Stream_Seek(s, credssp->identity.PasswordLength);
848 credssp->identity.PasswordLength /= 2;
850 credssp->identity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
853 int credssp_write_ts_password_creds(rdpCredssp* credssp, wStream* s)
856 int innerSize = credssp_sizeof_ts_password_creds(credssp);
858 /* TSPasswordCreds (SEQUENCE) */
860 size += ber_write_sequence_tag(s, innerSize);
862 /* [0] domainName (OCTET STRING) */
863 size += ber_write_sequence_octet_string(s, 0, (BYTE*) credssp->identity.Domain, credssp->identity.DomainLength * 2);
865 /* [1] userName (OCTET STRING) */
866 size += ber_write_sequence_octet_string(s, 1, (BYTE*) credssp->identity.User, credssp->identity.UserLength * 2);
868 /* [2] password (OCTET STRING) */
869 size += ber_write_sequence_octet_string(s, 2, (BYTE*) credssp->identity.Password, credssp->identity.PasswordLength * 2);
874 int credssp_sizeof_ts_credentials(rdpCredssp* credssp)
878 size += ber_sizeof_integer(1);
879 size += ber_sizeof_contextual_tag(ber_sizeof_integer(1));
880 size += ber_sizeof_sequence_octet_string(ber_sizeof_sequence(credssp_sizeof_ts_password_creds(credssp)));
885 void credssp_read_ts_credentials(rdpCredssp* credssp, PSecBuffer ts_credentials)
889 int ts_password_creds_length;
891 s = Stream_New(ts_credentials->pvBuffer, ts_credentials->cbBuffer);
893 /* TSCredentials (SEQUENCE) */
894 ber_read_sequence_tag(s, &length);
896 /* [0] credType (INTEGER) */
897 ber_read_contextual_tag(s, 0, &length, TRUE);
898 ber_read_integer(s, NULL);
900 /* [1] credentials (OCTET STRING) */
901 ber_read_contextual_tag(s, 1, &length, TRUE);
902 ber_read_octet_string_tag(s, &ts_password_creds_length);
904 credssp_read_ts_password_creds(credssp, s);
906 Stream_Free(s, FALSE);
909 int credssp_write_ts_credentials(rdpCredssp* credssp, wStream* s)
912 int innerSize = credssp_sizeof_ts_credentials(credssp);
915 /* TSCredentials (SEQUENCE) */
916 size += ber_write_sequence_tag(s, innerSize);
918 /* [0] credType (INTEGER) */
919 size += ber_write_contextual_tag(s, 0, ber_sizeof_integer(1), TRUE);
920 size += ber_write_integer(s, 1);
922 /* [1] credentials (OCTET STRING) */
924 passwordSize = ber_sizeof_sequence(credssp_sizeof_ts_password_creds(credssp));
926 size += ber_write_contextual_tag(s, 1, ber_sizeof_octet_string(passwordSize), TRUE);
927 size += ber_write_octet_string_tag(s, passwordSize);
928 size += credssp_write_ts_password_creds(credssp, s);
934 * Encode TSCredentials structure.
938 void credssp_encode_ts_credentials(rdpCredssp* credssp)
946 DomainLength = credssp->identity.DomainLength;
947 UserLength = credssp->identity.UserLength;
948 PasswordLength = credssp->identity.PasswordLength;
950 if (credssp->settings->RestrictedAdminModeRequired)
952 credssp->identity.DomainLength = 0;
953 credssp->identity.UserLength = 0;
954 credssp->identity.PasswordLength = 0;
957 length = ber_sizeof_sequence(credssp_sizeof_ts_credentials(credssp));
958 sspi_SecBufferAlloc(&credssp->ts_credentials, length);
960 s = Stream_New(credssp->ts_credentials.pvBuffer, length);
961 credssp_write_ts_credentials(credssp, s);
963 if (credssp->settings->RestrictedAdminModeRequired)
965 credssp->identity.DomainLength = DomainLength;
966 credssp->identity.UserLength = UserLength;
967 credssp->identity.PasswordLength = PasswordLength;
970 Stream_Free(s, FALSE);
973 SECURITY_STATUS credssp_encrypt_ts_credentials(rdpCredssp* credssp)
975 SecBuffer Buffers[2];
976 SecBufferDesc Message;
977 SECURITY_STATUS status;
979 credssp_encode_ts_credentials(credssp);
981 Buffers[0].BufferType = SECBUFFER_TOKEN; /* Signature */
982 Buffers[1].BufferType = SECBUFFER_DATA; /* TSCredentials */
984 sspi_SecBufferAlloc(&credssp->authInfo, credssp->ContextSizes.cbMaxSignature + credssp->ts_credentials.cbBuffer);
986 Buffers[0].cbBuffer = credssp->ContextSizes.cbMaxSignature;
987 Buffers[0].pvBuffer = credssp->authInfo.pvBuffer;
988 ZeroMemory(Buffers[0].pvBuffer, Buffers[0].cbBuffer);
990 Buffers[1].cbBuffer = credssp->ts_credentials.cbBuffer;
991 Buffers[1].pvBuffer = &((BYTE*) credssp->authInfo.pvBuffer)[Buffers[0].cbBuffer];
992 CopyMemory(Buffers[1].pvBuffer, credssp->ts_credentials.pvBuffer, Buffers[1].cbBuffer);
994 Message.cBuffers = 2;
995 Message.ulVersion = SECBUFFER_VERSION;
996 Message.pBuffers = (PSecBuffer) &Buffers;
998 status = credssp->table->EncryptMessage(&credssp->context, 0, &Message, credssp->send_seq_num++);
1000 if (status != SEC_E_OK)
1006 SECURITY_STATUS credssp_decrypt_ts_credentials(rdpCredssp* credssp)
1011 SecBuffer Buffers[2];
1012 SecBufferDesc Message;
1013 SECURITY_STATUS status;
1015 Buffers[0].BufferType = SECBUFFER_TOKEN; /* Signature */
1016 Buffers[1].BufferType = SECBUFFER_DATA; /* TSCredentials */
1018 if (credssp->authInfo.cbBuffer < 1)
1020 fprintf(stderr, "credssp_decrypt_ts_credentials missing authInfo buffer\n");
1021 return SEC_E_INVALID_TOKEN;
1024 length = credssp->authInfo.cbBuffer;
1025 buffer = (BYTE*) malloc(length);
1026 CopyMemory(buffer, credssp->authInfo.pvBuffer, length);
1028 Buffers[0].cbBuffer = credssp->ContextSizes.cbMaxSignature;
1029 Buffers[0].pvBuffer = buffer;
1031 Buffers[1].cbBuffer = length - credssp->ContextSizes.cbMaxSignature;
1032 Buffers[1].pvBuffer = &buffer[credssp->ContextSizes.cbMaxSignature];
1034 Message.cBuffers = 2;
1035 Message.ulVersion = SECBUFFER_VERSION;
1036 Message.pBuffers = (PSecBuffer) &Buffers;
1038 status = credssp->table->DecryptMessage(&credssp->context, &Message, credssp->recv_seq_num++, &pfQOP);
1040 if (status != SEC_E_OK)
1043 credssp_read_ts_credentials(credssp, &Buffers[1]);
1050 int credssp_sizeof_nego_token(int length)
1052 length = ber_sizeof_octet_string(length);
1053 length += ber_sizeof_contextual_tag(length);
1057 int credssp_sizeof_nego_tokens(int length)
1059 length = credssp_sizeof_nego_token(length);
1060 length += ber_sizeof_sequence_tag(length);
1061 length += ber_sizeof_sequence_tag(length);
1062 length += ber_sizeof_contextual_tag(length);
1066 int credssp_sizeof_pub_key_auth(int length)
1068 length = ber_sizeof_octet_string(length);
1069 length += ber_sizeof_contextual_tag(length);
1073 int credssp_sizeof_auth_info(int length)
1075 length = ber_sizeof_octet_string(length);
1076 length += ber_sizeof_contextual_tag(length);
1080 int credssp_sizeof_ts_request(int length)
1082 length += ber_sizeof_integer(2);
1083 length += ber_sizeof_contextual_tag(3);
1088 * Send CredSSP message.
1092 void credssp_send(rdpCredssp* credssp)
1096 int ts_request_length;
1097 int nego_tokens_length;
1098 int pub_key_auth_length;
1099 int auth_info_length;
1101 nego_tokens_length = (credssp->negoToken.cbBuffer > 0) ? credssp_sizeof_nego_tokens(credssp->negoToken.cbBuffer) : 0;
1102 pub_key_auth_length = (credssp->pubKeyAuth.cbBuffer > 0) ? credssp_sizeof_pub_key_auth(credssp->pubKeyAuth.cbBuffer) : 0;
1103 auth_info_length = (credssp->authInfo.cbBuffer > 0) ? credssp_sizeof_auth_info(credssp->authInfo.cbBuffer) : 0;
1105 length = nego_tokens_length + pub_key_auth_length + auth_info_length;
1107 ts_request_length = credssp_sizeof_ts_request(length);
1109 s = Stream_New(NULL, ber_sizeof_sequence(ts_request_length));
1112 ber_write_sequence_tag(s, ts_request_length); /* SEQUENCE */
1115 ber_write_contextual_tag(s, 0, 3, TRUE);
1116 ber_write_integer(s, 2); /* INTEGER */
1118 /* [1] negoTokens (NegoData) */
1119 if (nego_tokens_length > 0)
1121 length = nego_tokens_length;
1123 length -= ber_write_contextual_tag(s, 1, ber_sizeof_sequence(ber_sizeof_sequence(ber_sizeof_sequence_octet_string(credssp->negoToken.cbBuffer))), TRUE); /* NegoData */
1124 length -= ber_write_sequence_tag(s, ber_sizeof_sequence(ber_sizeof_sequence_octet_string(credssp->negoToken.cbBuffer))); /* SEQUENCE OF NegoDataItem */
1125 length -= ber_write_sequence_tag(s, ber_sizeof_sequence_octet_string(credssp->negoToken.cbBuffer)); /* NegoDataItem */
1126 length -= ber_write_sequence_octet_string(s, 0, (BYTE*) credssp->negoToken.pvBuffer, credssp->negoToken.cbBuffer); /* OCTET STRING */
1128 // assert length == 0
1131 /* [2] authInfo (OCTET STRING) */
1132 if (auth_info_length > 0)
1134 length = auth_info_length;
1135 length -= ber_write_sequence_octet_string(s, 2, credssp->authInfo.pvBuffer, credssp->authInfo.cbBuffer);
1137 // assert length == 0
1140 /* [3] pubKeyAuth (OCTET STRING) */
1141 if (pub_key_auth_length > 0)
1143 length = pub_key_auth_length;
1144 length -= ber_write_sequence_octet_string(s, 3, credssp->pubKeyAuth.pvBuffer, credssp->pubKeyAuth.cbBuffer);
1146 // assert length == 0
1149 Stream_SealLength(s);
1151 transport_write(credssp->transport, s);
1153 Stream_Free(s, TRUE);
1157 * Receive CredSSP message.
1162 int credssp_recv(rdpCredssp* credssp)
1169 s = Stream_New(NULL, 4096);
1171 status = transport_read(credssp->transport, s);
1172 Stream_Length(s) = status;
1176 fprintf(stderr, "credssp_recv() error: %d\n", status);
1177 Stream_Free(s, TRUE);
1182 if(!ber_read_sequence_tag(s, &length) ||
1183 !ber_read_contextual_tag(s, 0, &length, TRUE) ||
1184 !ber_read_integer(s, &version))
1186 Stream_Free(s, TRUE);
1190 /* [1] negoTokens (NegoData) */
1191 if (ber_read_contextual_tag(s, 1, &length, TRUE) != FALSE)
1193 if (!ber_read_sequence_tag(s, &length) || /* SEQUENCE OF NegoDataItem */
1194 !ber_read_sequence_tag(s, &length) || /* NegoDataItem */
1195 !ber_read_contextual_tag(s, 0, &length, TRUE) || /* [0] negoToken */
1196 !ber_read_octet_string_tag(s, &length) || /* OCTET STRING */
1197 Stream_GetRemainingLength(s) < length)
1199 Stream_Free(s, TRUE);
1202 sspi_SecBufferAlloc(&credssp->negoToken, length);
1203 Stream_Read(s, credssp->negoToken.pvBuffer, length);
1204 credssp->negoToken.cbBuffer = length;
1207 /* [2] authInfo (OCTET STRING) */
1208 if (ber_read_contextual_tag(s, 2, &length, TRUE) != FALSE)
1210 if(!ber_read_octet_string_tag(s, &length) || /* OCTET STRING */
1211 Stream_GetRemainingLength(s) < length)
1213 Stream_Free(s, TRUE);
1216 sspi_SecBufferAlloc(&credssp->authInfo, length);
1217 Stream_Read(s, credssp->authInfo.pvBuffer, length);
1218 credssp->authInfo.cbBuffer = length;
1221 /* [3] pubKeyAuth (OCTET STRING) */
1222 if (ber_read_contextual_tag(s, 3, &length, TRUE) != FALSE)
1224 if(!ber_read_octet_string_tag(s, &length) || /* OCTET STRING */
1225 Stream_GetRemainingLength(s) < length)
1227 Stream_Free(s, TRUE);
1230 sspi_SecBufferAlloc(&credssp->pubKeyAuth, length);
1231 Stream_Read(s, credssp->pubKeyAuth.pvBuffer, length);
1232 credssp->pubKeyAuth.cbBuffer = length;
1235 Stream_Free(s, TRUE);
1240 void credssp_buffer_print(rdpCredssp* credssp)
1242 if (credssp->negoToken.cbBuffer > 0)
1244 fprintf(stderr, "CredSSP.negoToken (length = %d):\n", (int) credssp->negoToken.cbBuffer);
1245 winpr_HexDump(credssp->negoToken.pvBuffer, credssp->negoToken.cbBuffer);
1248 if (credssp->pubKeyAuth.cbBuffer > 0)
1250 fprintf(stderr, "CredSSP.pubKeyAuth (length = %d):\n", (int) credssp->pubKeyAuth.cbBuffer);
1251 winpr_HexDump(credssp->pubKeyAuth.pvBuffer, credssp->pubKeyAuth.cbBuffer);
1254 if (credssp->authInfo.cbBuffer > 0)
1256 fprintf(stderr, "CredSSP.authInfo (length = %d):\n", (int) credssp->authInfo.cbBuffer);
1257 winpr_HexDump(credssp->authInfo.pvBuffer, credssp->authInfo.cbBuffer);
1261 void credssp_buffer_free(rdpCredssp* credssp)
1263 sspi_SecBufferFree(&credssp->negoToken);
1264 sspi_SecBufferFree(&credssp->pubKeyAuth);
1265 sspi_SecBufferFree(&credssp->authInfo);
1269 * Create new CredSSP state machine.
1271 * @return new CredSSP state machine.
1274 rdpCredssp* credssp_new(freerdp* instance, rdpTransport* transport, rdpSettings* settings)
1276 rdpCredssp* credssp;
1278 credssp = (rdpCredssp*) malloc(sizeof(rdpCredssp));
1279 ZeroMemory(credssp, sizeof(rdpCredssp));
1281 if (credssp != NULL)
1288 credssp->instance = instance;
1289 credssp->settings = settings;
1290 credssp->server = settings->ServerMode;
1291 credssp->transport = transport;
1292 credssp->send_seq_num = 0;
1293 credssp->recv_seq_num = 0;
1294 ZeroMemory(&credssp->negoToken, sizeof(SecBuffer));
1295 ZeroMemory(&credssp->pubKeyAuth, sizeof(SecBuffer));
1296 ZeroMemory(&credssp->authInfo, sizeof(SecBuffer));
1297 SecInvalidateHandle(&credssp->context);
1299 if (credssp->server)
1301 status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("Software\\FreeRDP\\Server"),
1302 0, KEY_READ | KEY_WOW64_64KEY, &hKey);
1304 if (status == ERROR_SUCCESS)
1306 status = RegQueryValueEx(hKey, _T("SspiModule"), NULL, &dwType, NULL, &dwSize);
1308 if (status == ERROR_SUCCESS)
1310 credssp->SspiModule = (LPTSTR) malloc(dwSize + sizeof(TCHAR));
1312 status = RegQueryValueEx(hKey, _T("SspiModule"), NULL, &dwType,
1313 (BYTE*) credssp->SspiModule, &dwSize);
1315 if (status == ERROR_SUCCESS)
1317 _tprintf(_T("Using SSPI Module: %s\n"), credssp->SspiModule);
1329 * Free CredSSP state machine.
1333 void credssp_free(rdpCredssp* credssp)
1335 if (credssp != NULL)
1338 credssp->table->DeleteSecurityContext(&credssp->context);
1340 sspi_SecBufferFree(&credssp->PublicKey);
1341 sspi_SecBufferFree(&credssp->ts_credentials);
1343 free(credssp->ServicePrincipalName);
1345 free(credssp->identity.User);
1346 free(credssp->identity.Domain);
1347 free(credssp->identity.Password);