--- /dev/null
+/**
+ * WinPR: Windows Portable Runtime
+ * Network Level Authentication (NLA)
+ *
+ * Copyright 2010-2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <time.h>
+
+#ifndef _WIN32
+#include <unistd.h>
+#endif
+
+#include <freerdp/crypto/nla.h>
+#include <freerdp/crypto/tls.h>
+
+#include <winpr/crt.h>
+#include <winpr/sspi.h>
+#include <winpr/print.h>
+
+/**
+ * TSRequest ::= SEQUENCE {
+ * version [0] INTEGER,
+ * negoTokens [1] NegoData OPTIONAL,
+ * authInfo [2] OCTET STRING OPTIONAL,
+ * pubKeyAuth [3] OCTET STRING OPTIONAL
+ * }
+ *
+ * NegoData ::= SEQUENCE OF NegoDataItem
+ *
+ * NegoDataItem ::= SEQUENCE {
+ * negoToken [0] OCTET STRING
+ * }
+ *
+ * TSCredentials ::= SEQUENCE {
+ * credType [0] INTEGER,
+ * credentials [1] OCTET STRING
+ * }
+ *
+ * TSPasswordCreds ::= SEQUENCE {
+ * domainName [0] OCTET STRING,
+ * userName [1] OCTET STRING,
+ * password [2] OCTET STRING
+ * }
+ *
+ * TSSmartCardCreds ::= SEQUENCE {
+ * pin [0] OCTET STRING,
+ * cspData [1] TSCspDataDetail,
+ * userHint [2] OCTET STRING OPTIONAL,
+ * domainHint [3] OCTET STRING OPTIONAL
+ * }
+ *
+ * TSCspDataDetail ::= SEQUENCE {
+ * keySpec [0] INTEGER,
+ * cardName [1] OCTET STRING OPTIONAL,
+ * readerName [2] OCTET STRING OPTIONAL,
+ * containerName [3] OCTET STRING OPTIONAL,
+ * cspName [4] OCTET STRING OPTIONAL
+ * }
+ *
+ */
+
+#ifdef WITH_DEBUG_NLA
+#define WITH_DEBUG_CREDSSP
+#endif
+
+void credssp_send(rdpCredssp* credssp);
+int credssp_recv(rdpCredssp* credssp);
+void credssp_buffer_print(rdpCredssp* credssp);
+void credssp_buffer_free(rdpCredssp* credssp);
+SECURITY_STATUS credssp_verify_public_key_echo(rdpCredssp* credssp);
+void credssp_encode_ts_credentials(rdpCredssp* credssp);
+SECURITY_STATUS credssp_encrypt_ts_credentials(rdpCredssp* credssp);
+SECURITY_STATUS credssp_decrypt_ts_credentials(rdpCredssp* credssp);
+
+/**
+ * Initialize NTLMSSP authentication module (client).
+ * @param credssp
+ */
+
+int credssp_ntlm_client_init(rdpCredssp* credssp)
+{
+ freerdp* instance;
+ rdpSettings* settings = credssp->settings;
+ instance = (freerdp*) settings->instance;
+
+ if ((settings->password == NULL) || (settings->username == NULL))
+ {
+ if (instance->Authenticate)
+ {
+ boolean proceed = instance->Authenticate(instance,
+ &settings->username, &settings->password, &settings->domain);
+ if (!proceed)
+ return 0;
+ }
+ }
+
+ sspi_SetAuthIdentity(&(credssp->identity), settings->username, settings->domain, settings->password);
+
+ sspi_SecBufferAlloc(&credssp->PublicKey, credssp->tls->public_key.length);
+ CopyMemory(credssp->PublicKey.pvBuffer, credssp->tls->public_key.data, credssp->tls->public_key.length);
+
+ return 1;
+}
+
+/**
+ * Initialize NTLMSSP authentication module (server).
+ * @param credssp
+ */
+
+int credssp_ntlm_server_init(rdpCredssp* credssp)
+{
+ freerdp* instance;
+ rdpSettings* settings = credssp->settings;
+ instance = (freerdp*) settings->instance;
+
+ sspi_SetAuthIdentity(&(credssp->identity), "username", NULL, NULL);
+
+ sspi_SecBufferAlloc(&credssp->PublicKey, credssp->tls->public_key.length);
+ CopyMemory(credssp->PublicKey.pvBuffer, credssp->tls->public_key.data, credssp->tls->public_key.length);
+
+ return 1;
+}
+
+int credssp_client_authenticate(rdpCredssp* credssp)
+{
+ ULONG cbMaxToken;
+ ULONG fContextReq;
+ ULONG pfContextAttr;
+ SECURITY_STATUS status;
+ CredHandle credentials;
+ TimeStamp expiration;
+ PSecPkgInfo pPackageInfo;
+ PSecBuffer p_buffer;
+ SecBuffer input_buffer;
+ SecBuffer output_buffer;
+ SecBufferDesc input_buffer_desc;
+ SecBufferDesc output_buffer_desc;
+ boolean have_context;
+ boolean have_input_buffer;
+ boolean have_pub_key_auth;
+
+ sspi_GlobalInit();
+
+ if (credssp_ntlm_client_init(credssp) == 0)
+ return 0;
+
+#ifdef NATIVE_SSPI
+ {
+ HMODULE hSSPI;
+ INIT_SECURITY_INTERFACE InitSecurityInterface;
+ PSecurityFunctionTable pSecurityInterface = NULL;
+
+ hSSPI = LoadLibrary(_T("secur32.dll"));
+
+#ifdef UNICODE
+ InitSecurityInterface = (INIT_SECURITY_INTERFACE) GetProcAddress(hSSPI, "InitSecurityInterfaceW");
+#else
+ InitSecurityInterface = (INIT_SECURITY_INTERFACE) GetProcAddress(hSSPI, "InitSecurityInterfaceA");
+#endif
+ credssp->table = (*InitSecurityInterface)();
+ }
+#else
+ credssp->table = InitSecurityInterface();
+#endif
+
+ status = credssp->table->QuerySecurityPackageInfo(NTLMSP_NAME, &pPackageInfo);
+
+ if (status != SEC_E_OK)
+ {
+ printf("QuerySecurityPackageInfo status: 0x%08X\n", status);
+ return 0;
+ }
+
+ cbMaxToken = pPackageInfo->cbMaxToken;
+
+ status = credssp->table->AcquireCredentialsHandle(NULL, NTLMSP_NAME,
+ SECPKG_CRED_OUTBOUND, NULL, &credssp->identity, NULL, NULL, &credentials, &expiration);
+
+ if (status != SEC_E_OK)
+ {
+ printf("AcquireCredentialsHandle status: 0x%08X\n", status);
+ return 0;
+ }
+
+ have_context = false;
+ have_input_buffer = false;
+ have_pub_key_auth = false;
+ memset(&input_buffer, 0, sizeof(SecBuffer));
+ memset(&output_buffer, 0, sizeof(SecBuffer));
+ memset(&credssp->ContextSizes, 0, sizeof(SecPkgContext_Sizes));
+
+ fContextReq = ISC_REQ_REPLAY_DETECT | ISC_REQ_SEQUENCE_DETECT |
+ ISC_REQ_CONFIDENTIALITY | ISC_REQ_DELEGATE;
+
+ while (true)
+ {
+ output_buffer_desc.ulVersion = SECBUFFER_VERSION;
+ output_buffer_desc.cBuffers = 1;
+ output_buffer_desc.pBuffers = &output_buffer;
+ output_buffer.BufferType = SECBUFFER_TOKEN;
+ output_buffer.cbBuffer = cbMaxToken;
+ output_buffer.pvBuffer = malloc(output_buffer.cbBuffer);
+
+ status = credssp->table->InitializeSecurityContext(&credentials,
+ (have_context) ? &credssp->context : NULL,
+ NULL, fContextReq, 0, SECURITY_NETWORK_DREP,
+ (have_input_buffer) ? &input_buffer_desc : NULL,
+ 0, &credssp->context, &output_buffer_desc, &pfContextAttr, &expiration);
+
+ if (input_buffer.pvBuffer != NULL)
+ {
+ free(input_buffer.pvBuffer);
+ input_buffer.pvBuffer = NULL;
+ }
+
+ if ((status == SEC_I_COMPLETE_AND_CONTINUE) || (status == SEC_I_COMPLETE_NEEDED) || (status == SEC_E_OK))
+ {
+ if (credssp->table->CompleteAuthToken != NULL)
+ credssp->table->CompleteAuthToken(&credssp->context, &output_buffer_desc);
+
+ have_pub_key_auth = true;
+
+ if (credssp->table->QueryContextAttributes(&credssp->context, SECPKG_ATTR_SIZES, &credssp->ContextSizes) != SEC_E_OK)
+ {
+ printf("QueryContextAttributes SECPKG_ATTR_SIZES failure\n");
+ return 0;
+ }
+
+ if (have_pub_key_auth)
+ {
+ BYTE* p;
+ SecBuffer Buffers[2];
+ SecBufferDesc Message;
+ SECURITY_STATUS encrypt_status;
+
+ Buffers[0].BufferType = SECBUFFER_TOKEN; /* Signature */
+ Buffers[1].BufferType = SECBUFFER_DATA; /* TLS Public Key */
+
+ Buffers[0].cbBuffer = credssp->ContextSizes.cbMaxSignature;
+ Buffers[0].pvBuffer = xzalloc(Buffers[0].cbBuffer);
+
+ Buffers[1].cbBuffer = credssp->PublicKey.cbBuffer;
+ Buffers[1].pvBuffer = malloc(Buffers[1].cbBuffer);
+ CopyMemory(Buffers[1].pvBuffer, credssp->PublicKey.pvBuffer, Buffers[1].cbBuffer);
+
+ Message.cBuffers = 2;
+ Message.ulVersion = SECBUFFER_VERSION;
+ Message.pBuffers = (PSecBuffer) &Buffers;
+
+ sspi_SecBufferAlloc(&credssp->pubKeyAuth, Buffers[0].cbBuffer + Buffers[1].cbBuffer);
+
+ encrypt_status = credssp->table->EncryptMessage(&credssp->context, 0, &Message, 0);
+
+ if (encrypt_status != SEC_E_OK)
+ {
+ printf("EncryptMessage status: 0x%08X\n", encrypt_status);
+ return 0;
+ }
+
+#ifdef WITH_DEBUG_CREDSSP
+ printf("CredSSP.Signature: (%d)\n", (int) Buffers[0].cbBuffer);
+ winpr_HexDump((BYTE*) Buffers[0].pvBuffer, Buffers[0].cbBuffer);
+ printf("CredSSP.PublicKey: (%d)\n", (int) credssp->PublicKey.cbBuffer);
+ winpr_HexDump((BYTE*) credssp->PublicKey.pvBuffer, credssp->PublicKey.cbBuffer);
+ printf("CredSSP.PublicKey (encrypted) (%d):\n", (int) Buffers[1].cbBuffer);
+ winpr_HexDump((BYTE*) Buffers[1].pvBuffer, Buffers[1].cbBuffer);
+#endif
+
+ p = (BYTE*) credssp->pubKeyAuth.pvBuffer;
+ CopyMemory(p, Buffers[0].pvBuffer, Buffers[0].cbBuffer); /* Message Signature */
+ CopyMemory(&p[Buffers[0].cbBuffer], Buffers[1].pvBuffer, Buffers[1].cbBuffer); /* Encrypted Public Key */
+ free(Buffers[0].pvBuffer);
+ free(Buffers[1].pvBuffer);
+ }
+
+ if (status == SEC_I_COMPLETE_NEEDED)
+ status = SEC_E_OK;
+ else if (status == SEC_I_COMPLETE_AND_CONTINUE)
+ status = SEC_I_CONTINUE_NEEDED;
+ }
+
+ /* send authentication token to server */
+
+ if (output_buffer.cbBuffer > 0)
+ {
+ p_buffer = &output_buffer_desc.pBuffers[0];
+
+ credssp->negoToken.pvBuffer = p_buffer->pvBuffer;
+ credssp->negoToken.cbBuffer = p_buffer->cbBuffer;
+
+#ifdef WITH_DEBUG_CREDSSP
+ printf("Sending Authentication Token\n");
+ winpr_HexDump(credssp->negoToken.pvBuffer, credssp->negoToken.cbBuffer);
+#endif
+
+ credssp_send(credssp);
+ credssp_buffer_free(credssp);
+ }
+
+ if (status != SEC_I_CONTINUE_NEEDED)
+ break;
+
+ /* receive server response and place in input buffer */
+
+ input_buffer_desc.ulVersion = SECBUFFER_VERSION;
+ input_buffer_desc.cBuffers = 1;
+ input_buffer_desc.pBuffers = &input_buffer;
+ input_buffer.BufferType = SECBUFFER_TOKEN;
+
+ if (credssp_recv(credssp) < 0)
+ return -1;
+
+#ifdef WITH_DEBUG_CREDSSP
+ printf("Receiving Authentication Token\n");
+ winpr_HexDump(credssp->negoToken.pvBuffer, credssp->negoToken.cbBuffer);
+#endif
+
+ p_buffer = &input_buffer_desc.pBuffers[0];
+ p_buffer->pvBuffer = credssp->negoToken.pvBuffer;
+ p_buffer->cbBuffer = credssp->negoToken.cbBuffer;
+
+ have_input_buffer = true;
+ have_context = true;
+ }
+
+ /* Encrypted Public Key +1 */
+ if (credssp_recv(credssp) < 0)
+ return -1;
+
+ /* Verify Server Public Key Echo */
+
+ status = credssp_verify_public_key_echo(credssp);
+ credssp_buffer_free(credssp);
+
+ if (status != SEC_E_OK)
+ return 0;
+
+ /* Send encrypted credentials */
+
+ status = credssp_encrypt_ts_credentials(credssp);
+
+ if (status != SEC_E_OK)
+ {
+ printf("credssp_encrypt_ts_credentials status: 0x%08X\n", status);
+ return 0;
+ }
+
+ credssp_send(credssp);
+ credssp_buffer_free(credssp);
+
+ /* Free resources */
+
+ credssp->table->FreeCredentialsHandle(&credentials);
+ credssp->table->FreeContextBuffer(pPackageInfo);
+
+ return 1;
+}
+
+/**
+ * Authenticate with client using CredSSP (server).
+ * @param credssp
+ * @return 1 if authentication is successful
+ */
+
+int credssp_server_authenticate(rdpCredssp* credssp)
+{
+ UINT32 cbMaxToken;
+ ULONG fContextReq;
+ ULONG pfContextAttr;
+ SECURITY_STATUS status;
+ CredHandle credentials;
+ TimeStamp expiration;
+ PSecPkgInfo pPackageInfo;
+ PSecBuffer p_buffer;
+ SecBuffer input_buffer;
+ SecBuffer output_buffer;
+ SecBufferDesc input_buffer_desc;
+ SecBufferDesc output_buffer_desc;
+ boolean have_context;
+ boolean have_input_buffer;
+ boolean have_pub_key_auth;
+
+ sspi_GlobalInit();
+
+ if (credssp_ntlm_server_init(credssp) == 0)
+ return 0;
+
+#ifdef NATIVE_SSPI
+ {
+ HMODULE hSSPI;
+ INIT_SECURITY_INTERFACE InitSecurityInterface;
+ PSecurityFunctionTable pSecurityInterface = NULL;
+
+ hSSPI = LoadLibrary(_T("secur32.dll"));
+
+#ifdef UNICODE
+ InitSecurityInterface = (INIT_SECURITY_INTERFACE) GetProcAddress(hSSPI, "InitSecurityInterfaceW");
+#else
+ InitSecurityInterface = (INIT_SECURITY_INTERFACE) GetProcAddress(hSSPI, "InitSecurityInterfaceA");
+#endif
+ credssp->table = (*InitSecurityInterface)();
+ }
+#else
+ credssp->table = InitSecurityInterface();
+#endif
+
+ status = credssp->table->QuerySecurityPackageInfo(NTLMSP_NAME, &pPackageInfo);
+
+ if (status != SEC_E_OK)
+ {
+ printf("QuerySecurityPackageInfo status: 0x%08X\n", status);
+ return 0;
+ }
+
+ cbMaxToken = pPackageInfo->cbMaxToken;
+
+ status = credssp->table->AcquireCredentialsHandle(NULL, NTLMSP_NAME,
+ SECPKG_CRED_INBOUND, NULL, &credssp->identity, NULL, NULL, &credentials, &expiration);
+
+ if (status != SEC_E_OK)
+ {
+ printf("AcquireCredentialsHandle status: 0x%08X\n", status);
+ return 0;
+ }
+
+ have_context = false;
+ have_input_buffer = false;
+ have_pub_key_auth = false;
+ memset(&input_buffer, 0, sizeof(SecBuffer));
+ memset(&output_buffer, 0, sizeof(SecBuffer));
+ memset(&credssp->ContextSizes, 0, sizeof(SecPkgContext_Sizes));
+
+ fContextReq = ASC_REQ_REPLAY_DETECT | ASC_REQ_SEQUENCE_DETECT |
+ ASC_REQ_CONFIDENTIALITY | ASC_REQ_DELEGATE;
+
+ while (true)
+ {
+ input_buffer_desc.ulVersion = SECBUFFER_VERSION;
+ input_buffer_desc.cBuffers = 1;
+ input_buffer_desc.pBuffers = &input_buffer;
+ input_buffer.BufferType = SECBUFFER_TOKEN;
+
+ /* receive authentication token */
+
+ input_buffer_desc.ulVersion = SECBUFFER_VERSION;
+ input_buffer_desc.cBuffers = 1;
+ input_buffer_desc.pBuffers = &input_buffer;
+ input_buffer.BufferType = SECBUFFER_TOKEN;
+
+ if (credssp_recv(credssp) < 0)
+ return -1;
+
+#ifdef WITH_DEBUG_CREDSSP
+ printf("Receiving Authentication Token\n");
+ credssp_buffer_print(credssp);
+#endif
+
+ p_buffer = &input_buffer_desc.pBuffers[0];
+ p_buffer->pvBuffer = credssp->negoToken.pvBuffer;
+ p_buffer->cbBuffer = credssp->negoToken.cbBuffer;
+
+ output_buffer_desc.ulVersion = SECBUFFER_VERSION;
+ output_buffer_desc.cBuffers = 1;
+ output_buffer_desc.pBuffers = &output_buffer;
+ output_buffer.BufferType = SECBUFFER_TOKEN;
+ output_buffer.cbBuffer = cbMaxToken;
+ output_buffer.pvBuffer = malloc(output_buffer.cbBuffer);
+
+ status = credssp->table->AcceptSecurityContext(&credentials,
+ have_context? &credssp->context: NULL,
+ &input_buffer_desc, fContextReq, SECURITY_NETWORK_DREP, &credssp->context,
+ &output_buffer_desc, &pfContextAttr, &expiration);
+
+ if (input_buffer.pvBuffer != NULL)
+ {
+ free(input_buffer.pvBuffer);
+ input_buffer.pvBuffer = NULL;
+ }
+
+ p_buffer = &output_buffer_desc.pBuffers[0];
+ credssp->negoToken.pvBuffer = p_buffer->pvBuffer;
+ credssp->negoToken.cbBuffer = p_buffer->cbBuffer;
+
+ if ((status == SEC_I_COMPLETE_AND_CONTINUE) || (status == SEC_I_COMPLETE_NEEDED))
+ {
+ if (credssp->table->CompleteAuthToken != NULL)
+ credssp->table->CompleteAuthToken(&credssp->context, &output_buffer_desc);
+
+ have_pub_key_auth = true;
+
+ if (credssp->table->QueryContextAttributes(&credssp->context, SECPKG_ATTR_SIZES, &credssp->ContextSizes) != SEC_E_OK)
+ {
+ printf("QueryContextAttributes SECPKG_ATTR_SIZES failure\n");
+ return 0;
+ }
+
+ credssp_verify_public_key_echo(credssp);
+
+ sspi_SecBufferFree(&credssp->negoToken);
+ credssp->negoToken.pvBuffer = NULL;
+ credssp->negoToken.cbBuffer = 0;
+
+ if (have_pub_key_auth)
+ {
+ BYTE* p;
+ SecBuffer Buffers[2];
+ SecBufferDesc Message;
+
+ Buffers[0].BufferType = SECBUFFER_DATA; /* TLS Public Key */
+ Buffers[1].BufferType = SECBUFFER_TOKEN; /* Signature */
+
+ Buffers[0].cbBuffer = credssp->PublicKey.cbBuffer;
+ Buffers[0].pvBuffer = malloc(Buffers[0].cbBuffer);
+ CopyMemory(Buffers[0].pvBuffer, credssp->PublicKey.pvBuffer, Buffers[0].cbBuffer);
+
+ Buffers[1].cbBuffer = credssp->ContextSizes.cbMaxSignature;
+ Buffers[1].pvBuffer = xzalloc(Buffers[1].cbBuffer);
+
+ Message.cBuffers = 2;
+ Message.ulVersion = SECBUFFER_VERSION;
+ Message.pBuffers = (PSecBuffer) &Buffers;
+
+ p = (BYTE*) Buffers[0].pvBuffer;
+ p[0]++; /* Public Key +1 */
+
+ sspi_SecBufferAlloc(&credssp->pubKeyAuth, Buffers[0].cbBuffer + Buffers[1].cbBuffer);
+
+ credssp->table->EncryptMessage(&credssp->context, 0, &Message, 0);
+
+ p = (BYTE*) credssp->pubKeyAuth.pvBuffer;
+ CopyMemory(p, Buffers[1].pvBuffer, Buffers[1].cbBuffer); /* Message Signature */
+ CopyMemory(&p[Buffers[1].cbBuffer], Buffers[0].pvBuffer, Buffers[0].cbBuffer); /* Encrypted Public Key */
+ }
+
+ if (status == SEC_I_COMPLETE_NEEDED)
+ status = SEC_E_OK;
+ else if (status == SEC_I_COMPLETE_AND_CONTINUE)
+ status = SEC_I_CONTINUE_NEEDED;
+ }
+
+ /* send authentication token */
+
+#ifdef WITH_DEBUG_CREDSSP
+ printf("Sending Authentication Token\n");
+ credssp_buffer_print(credssp);
+#endif
+
+ credssp_send(credssp);
+ credssp_buffer_free(credssp);
+
+ if (status != SEC_I_CONTINUE_NEEDED)
+ break;
+
+ have_context = true;
+ }
+
+ /* Receive encrypted credentials */
+
+ if (credssp_recv(credssp) < 0)
+ return -1;
+
+ credssp_decrypt_ts_credentials(credssp);
+
+ if (status != SEC_E_OK)
+ {
+ printf("AcceptSecurityContext status: 0x%08X\n", status);
+ return 0;
+ }
+
+ status = credssp->table->ImpersonateSecurityContext(&credssp->context);
+
+ if (status != SEC_E_OK)
+ {
+ printf("ImpersonateSecurityContext status: 0x%08X\n", status);
+ return 0;
+ }
+ else
+ {
+ status = credssp->table->RevertSecurityContext(&credssp->context);
+
+ if (status != SEC_E_OK)
+ {
+ printf("RevertSecurityContext status: 0x%08X\n", status);
+ return 0;
+ }
+ }
+
+ credssp->table->FreeContextBuffer(pPackageInfo);
+
+ return 1;
+}
+
+/**
+ * Authenticate using CredSSP.
+ * @param credssp
+ * @return 1 if authentication is successful
+ */
+
+int credssp_authenticate(rdpCredssp* credssp)
+{
+ if (credssp->server)
+ return credssp_server_authenticate(credssp);
+ else
+ return credssp_client_authenticate(credssp);
+}
+
+SECURITY_STATUS credssp_verify_public_key_echo(rdpCredssp* credssp)
+{
+ int length;
+ ULONG pfQOP;
+ BYTE* public_key1;
+ BYTE* public_key2;
+ BYTE* pub_key_auth;
+ int public_key_length;
+ SecBuffer Buffers[2];
+ SecBufferDesc Message;
+ SECURITY_STATUS status;
+
+ length = credssp->pubKeyAuth.cbBuffer;
+ pub_key_auth = (BYTE*) credssp->pubKeyAuth.pvBuffer;
+ public_key_length = credssp->PublicKey.cbBuffer;
+
+ Buffers[0].BufferType = SECBUFFER_TOKEN; /* Signature */
+ Buffers[1].BufferType = SECBUFFER_DATA; /* Encrypted TLS Public Key */
+
+ Buffers[0].cbBuffer = credssp->ContextSizes.cbMaxSignature;
+ Buffers[0].pvBuffer = malloc(Buffers[0].cbBuffer);
+ CopyMemory(Buffers[0].pvBuffer, pub_key_auth, Buffers[0].cbBuffer);
+
+ Buffers[1].cbBuffer = length - Buffers[0].cbBuffer;
+ Buffers[1].pvBuffer = malloc(Buffers[1].cbBuffer);
+ CopyMemory(Buffers[1].pvBuffer, &pub_key_auth[Buffers[0].cbBuffer], Buffers[1].cbBuffer);
+
+ Message.cBuffers = 2;
+ Message.ulVersion = SECBUFFER_VERSION;
+ Message.pBuffers = (PSecBuffer) &Buffers;
+
+ status = credssp->table->DecryptMessage(&credssp->context, &Message, 0, &pfQOP);
+
+ if (status != SEC_E_OK)
+ {
+ printf("DecryptMessage failure: 0x%08X\n", status);
+ return status;
+ }
+
+ public_key1 = (BYTE*) credssp->PublicKey.pvBuffer;
+ public_key2 = (BYTE*) Buffers[1].pvBuffer;
+
+ if (!credssp->server)
+ public_key2[0]--; /* server echos the public key +1 */
+
+ if (memcmp(public_key1, public_key2, public_key_length) != 0)
+ {
+ printf("Could not verify server's public key echo\n");
+
+ printf("Expected (length = %d):\n", public_key_length);
+ winpr_HexDump(public_key1, public_key_length);
+
+ printf("Actual (length = %d):\n", public_key_length);
+ winpr_HexDump(public_key2, public_key_length);
+
+ return SEC_E_MESSAGE_ALTERED; /* DO NOT SEND CREDENTIALS! */
+ }
+
+ public_key2[0]++;
+
+ free(Buffers[0].pvBuffer);
+ free(Buffers[1].pvBuffer);
+
+ return SEC_E_OK;
+}
+
+int credssp_skip_ts_password_creds(rdpCredssp* credssp)
+{
+ int length;
+ int ts_password_creds_length = 0;
+
+ length = ber_skip_octet_string(credssp->identity.DomainLength);
+ length += ber_skip_contextual_tag(length);
+ ts_password_creds_length += length;
+
+ length = ber_skip_octet_string(credssp->identity.UserLength);
+ length += ber_skip_contextual_tag(length);
+ ts_password_creds_length += length;
+
+ length = ber_skip_octet_string(credssp->identity.PasswordLength);
+ length += ber_skip_contextual_tag(length);
+ ts_password_creds_length += length;
+
+ length = ber_skip_sequence(ts_password_creds_length);
+
+ return length;
+}
+
+void credssp_read_ts_password_creds(rdpCredssp* credssp, STREAM* s)
+{
+ int length;
+
+ /* TSPasswordCreds (SEQUENCE) */
+ ber_read_sequence_tag(s, &length);
+
+ /* [0] domainName (OCTET STRING) */
+ ber_read_contextual_tag(s, 0, &length, true);
+ ber_read_octet_string_tag(s, &length);
+ credssp->identity.DomainLength = (UINT32) length;
+ credssp->identity.Domain = (UINT16*) malloc(length);
+ CopyMemory(credssp->identity.Domain, s->p, credssp->identity.DomainLength);
+ stream_seek(s, credssp->identity.DomainLength);
+
+ /* [1] userName (OCTET STRING) */
+ ber_read_contextual_tag(s, 1, &length, true);
+ ber_read_octet_string_tag(s, &length);
+ credssp->identity.UserLength = (UINT32) length;
+ credssp->identity.User = (UINT16*) malloc(length);
+ CopyMemory(credssp->identity.User, s->p, credssp->identity.UserLength);
+ stream_seek(s, credssp->identity.UserLength);
+
+ /* [2] password (OCTET STRING) */
+ ber_read_contextual_tag(s, 2, &length, true);
+ ber_read_octet_string_tag(s, &length);
+ credssp->identity.PasswordLength = (UINT32) length;
+ credssp->identity.Password = (UINT16*) malloc(length);
+ CopyMemory(credssp->identity.Password, s->p, credssp->identity.PasswordLength);
+ stream_seek(s, credssp->identity.PasswordLength);
+}
+
+void credssp_write_ts_password_creds(rdpCredssp* credssp, STREAM* s)
+{
+ int length;
+
+ length = credssp_skip_ts_password_creds(credssp);
+
+ /* TSPasswordCreds (SEQUENCE) */
+ length = ber_get_content_length(length);
+ ber_write_sequence_tag(s, length);
+
+ /* [0] domainName (OCTET STRING) */
+ ber_write_contextual_tag(s, 0, credssp->identity.DomainLength + 2, true);
+ ber_write_octet_string(s, (BYTE*) credssp->identity.Domain, credssp->identity.DomainLength);
+
+ /* [1] userName (OCTET STRING) */
+ ber_write_contextual_tag(s, 1, credssp->identity.UserLength + 2, true);
+ ber_write_octet_string(s, (BYTE*) credssp->identity.User, credssp->identity.UserLength);
+
+ /* [2] password (OCTET STRING) */
+ ber_write_contextual_tag(s, 2, credssp->identity.PasswordLength + 2, true);
+ ber_write_octet_string(s, (BYTE*) credssp->identity.Password, credssp->identity.PasswordLength);
+}
+
+int credssp_skip_ts_credentials(rdpCredssp* credssp)
+{
+ int length;
+ int ts_password_creds_length;
+ int ts_credentials_length = 0;
+
+ length = ber_skip_integer(0);
+ length += ber_skip_contextual_tag(length);
+ ts_credentials_length += length;
+
+ ts_password_creds_length = credssp_skip_ts_password_creds(credssp);
+ length = ber_skip_octet_string(ts_password_creds_length);
+ length += ber_skip_contextual_tag(length);
+ ts_credentials_length += length;
+
+ length = ber_skip_sequence(ts_credentials_length);
+
+ return length;
+}
+
+void credssp_read_ts_credentials(rdpCredssp* credssp, PSecBuffer ts_credentials)
+{
+ STREAM* s;
+ int length;
+ int ts_password_creds_length;
+
+ s = stream_new(0);
+ stream_attach(s, ts_credentials->pvBuffer, ts_credentials->cbBuffer);
+
+ /* TSCredentials (SEQUENCE) */
+ ber_read_sequence_tag(s, &length);
+
+ /* [0] credType (INTEGER) */
+ ber_read_contextual_tag(s, 0, &length, true);
+ ber_read_integer(s, NULL);
+
+ /* [1] credentials (OCTET STRING) */
+ ber_read_contextual_tag(s, 1, &length, true);
+ ber_read_octet_string_tag(s, &ts_password_creds_length);
+
+ credssp_read_ts_password_creds(credssp, s);
+
+ stream_detach(s);
+ stream_free(s);
+}
+
+void credssp_write_ts_credentials(rdpCredssp* credssp, STREAM* s)
+{
+ int length;
+ int ts_password_creds_length;
+
+ length = credssp_skip_ts_credentials(credssp);
+ ts_password_creds_length = credssp_skip_ts_password_creds(credssp);
+
+ /* TSCredentials (SEQUENCE) */
+ length = ber_get_content_length(length);
+ length -= ber_write_sequence_tag(s, length);
+
+ /* [0] credType (INTEGER) */
+ length -= ber_write_contextual_tag(s, 0, 3, true);
+ length -= ber_write_integer(s, 1);
+
+ /* [1] credentials (OCTET STRING) */
+ length -= 1;
+ length -= ber_write_contextual_tag(s, 1, length, true);
+ length -= ber_write_octet_string_tag(s, ts_password_creds_length);
+
+ credssp_write_ts_password_creds(credssp, s);
+}
+
+/**
+ * Encode TSCredentials structure.
+ * @param credssp
+ */
+
+void credssp_encode_ts_credentials(rdpCredssp* credssp)
+{
+ STREAM* s;
+ int length;
+
+ s = stream_new(0);
+ length = credssp_skip_ts_credentials(credssp);
+ sspi_SecBufferAlloc(&credssp->ts_credentials, length);
+ stream_attach(s, credssp->ts_credentials.pvBuffer, length);
+
+ credssp_write_ts_credentials(credssp, s);
+ stream_detach(s);
+ stream_free(s);
+}
+
+SECURITY_STATUS credssp_encrypt_ts_credentials(rdpCredssp* credssp)
+{
+ BYTE* p;
+ SecBuffer Buffers[2];
+ SecBufferDesc Message;
+ SECURITY_STATUS status;
+
+ credssp_encode_ts_credentials(credssp);
+
+ Buffers[0].BufferType = SECBUFFER_TOKEN; /* Signature */
+ Buffers[1].BufferType = SECBUFFER_DATA; /* TSCredentials */
+
+ Buffers[0].cbBuffer = 16;
+ Buffers[0].pvBuffer = xzalloc(Buffers[0].cbBuffer);
+
+ Buffers[1].cbBuffer = credssp->ts_credentials.cbBuffer;
+ Buffers[1].pvBuffer = malloc(Buffers[1].cbBuffer);
+ CopyMemory(Buffers[1].pvBuffer, credssp->ts_credentials.pvBuffer, Buffers[1].cbBuffer);
+
+ Message.cBuffers = 2;
+ Message.ulVersion = SECBUFFER_VERSION;
+ Message.pBuffers = (PSecBuffer) &Buffers;
+
+ sspi_SecBufferAlloc(&credssp->authInfo, Buffers[0].cbBuffer + Buffers[1].cbBuffer);
+
+ status = credssp->table->EncryptMessage(&credssp->context, 0, &Message, 1);
+
+ if (status != SEC_E_OK)
+ return status;
+
+ p = (BYTE*) credssp->authInfo.pvBuffer;
+ CopyMemory(p, Buffers[0].pvBuffer, Buffers[0].cbBuffer); /* Message Signature */
+ CopyMemory(&p[Buffers[0].cbBuffer], Buffers[1].pvBuffer, Buffers[1].cbBuffer); /* Encrypted TSCredentials */
+
+ free(Buffers[0].pvBuffer);
+ free(Buffers[1].pvBuffer);
+
+ return SEC_E_OK;
+}
+
+SECURITY_STATUS credssp_decrypt_ts_credentials(rdpCredssp* credssp)
+{
+ BYTE* p;
+ SecBuffer Buffers[2];
+ SecBufferDesc Message;
+ SECURITY_STATUS status;
+
+ Buffers[0].BufferType = SECBUFFER_TOKEN; /* Signature */
+ Buffers[1].BufferType = SECBUFFER_DATA; /* TSCredentials */
+
+ Buffers[0].cbBuffer = 16;
+ Buffers[0].pvBuffer = malloc(Buffers[0].cbBuffer);
+ CopyMemory(Buffers[0].pvBuffer, credssp->authInfo.pvBuffer, Buffers[0].cbBuffer);
+
+ Buffers[1].cbBuffer = credssp->authInfo.cbBuffer - Buffers[0].cbBuffer;
+ Buffers[1].pvBuffer = malloc(Buffers[1].cbBuffer);
+ p = (BYTE*) credssp->authInfo.pvBuffer;
+ CopyMemory(Buffers[1].pvBuffer, &p[Buffers[0].cbBuffer], Buffers[1].cbBuffer);
+
+ Message.cBuffers = 2;
+ Message.ulVersion = SECBUFFER_VERSION;
+ Message.pBuffers = (PSecBuffer) &Buffers;
+
+ sspi_SecBufferAlloc(&credssp->authInfo, Buffers[0].cbBuffer + Buffers[1].cbBuffer);
+
+ status = credssp->table->DecryptMessage(&credssp->context, &Message, 1, 0);
+
+ if (status != SEC_E_OK)
+ return status;
+
+ credssp_read_ts_credentials(credssp, &Buffers[1]);
+
+ free(Buffers[0].pvBuffer);
+ free(Buffers[1].pvBuffer);
+
+ return SEC_E_OK;
+}
+
+int credssp_skip_nego_token(int length)
+{
+ length = ber_skip_octet_string(length);
+ length += ber_skip_contextual_tag(length);
+ return length;
+}
+
+int credssp_skip_nego_tokens(int length)
+{
+ length = credssp_skip_nego_token(length);
+ length += ber_skip_sequence_tag(length);
+ length += ber_skip_sequence_tag(length);
+ length += ber_skip_contextual_tag(length);
+ return length;
+}
+
+int credssp_skip_pub_key_auth(int length)
+{
+ length = ber_skip_octet_string(length);
+ length += ber_skip_contextual_tag(length);
+ return length;
+}
+
+int credssp_skip_auth_info(int length)
+{
+ length = ber_skip_octet_string(length);
+ length += ber_skip_contextual_tag(length);
+ return length;
+}
+
+int credssp_skip_ts_request(int length)
+{
+ length += ber_skip_integer(2);
+ length += ber_skip_contextual_tag(3);
+ length += ber_skip_sequence_tag(length);
+ return length;
+}
+
+/**
+ * Send CredSSP message.
+ * @param credssp
+ */
+
+void credssp_send(rdpCredssp* credssp)
+{
+ STREAM* s;
+ int length;
+ int ts_request_length;
+ int nego_tokens_length;
+ int pub_key_auth_length;
+ int auth_info_length;
+
+ nego_tokens_length = (credssp->negoToken.cbBuffer > 0) ? credssp_skip_nego_tokens(credssp->negoToken.cbBuffer) : 0;
+ pub_key_auth_length = (credssp->pubKeyAuth.cbBuffer > 0) ? credssp_skip_pub_key_auth(credssp->pubKeyAuth.cbBuffer) : 0;
+ auth_info_length = (credssp->authInfo.cbBuffer > 0) ? credssp_skip_auth_info(credssp->authInfo.cbBuffer) : 0;
+
+ length = nego_tokens_length + pub_key_auth_length + auth_info_length;
+ ts_request_length = credssp_skip_ts_request(length);
+
+ s = stream_new(ts_request_length);
+
+ /* TSRequest */
+ length = ber_get_content_length(ts_request_length);
+ ber_write_sequence_tag(s, length); /* SEQUENCE */
+ ber_write_contextual_tag(s, 0, 3, true); /* [0] version */
+ ber_write_integer(s, 2); /* INTEGER */
+
+ /* [1] negoTokens (NegoData) */
+ if (nego_tokens_length > 0)
+ {
+ length = ber_get_content_length(nego_tokens_length);
+ length -= ber_write_contextual_tag(s, 1, length, true); /* NegoData */
+ length -= ber_write_sequence_tag(s, length); /* SEQUENCE OF NegoDataItem */
+ length -= ber_write_sequence_tag(s, length); /* NegoDataItem */
+ length -= ber_write_contextual_tag(s, 0, length, true); /* [0] negoToken */
+ ber_write_octet_string(s, credssp->negoToken.pvBuffer, length); /* OCTET STRING */
+ }
+
+ /* [2] authInfo (OCTET STRING) */
+ if (auth_info_length > 0)
+ {
+ length = ber_get_content_length(auth_info_length);
+ length -= ber_write_contextual_tag(s, 2, length, true);
+ ber_write_octet_string(s, credssp->authInfo.pvBuffer, credssp->authInfo.cbBuffer);
+ }
+
+ /* [3] pubKeyAuth (OCTET STRING) */
+ if (pub_key_auth_length > 0)
+ {
+ length = ber_get_content_length(pub_key_auth_length);
+ length -= ber_write_contextual_tag(s, 3, length, true);
+ ber_write_octet_string(s, credssp->pubKeyAuth.pvBuffer, length);
+ }
+
+ tls_write(credssp->tls, s->data, stream_get_length(s));
+ stream_free(s);
+}
+
+/**
+ * Receive CredSSP message.
+ * @param credssp
+ * @return
+ */
+
+int credssp_recv(rdpCredssp* credssp)
+{
+ STREAM* s;
+ int length;
+ int status;
+ UINT32 version;
+
+ s = stream_new(2048);
+ status = tls_read(credssp->tls, s->data, stream_get_left(s));
+
+ if (status < 0)
+ {
+ stream_free(s) ;
+ return -1;
+ }
+
+ /* TSRequest */
+ ber_read_sequence_tag(s, &length);
+ ber_read_contextual_tag(s, 0, &length, true);
+ ber_read_integer(s, &version);
+
+ /* [1] negoTokens (NegoData) */
+ if (ber_read_contextual_tag(s, 1, &length, true) != false)
+ {
+ ber_read_sequence_tag(s, &length); /* SEQUENCE OF NegoDataItem */
+ ber_read_sequence_tag(s, &length); /* NegoDataItem */
+ ber_read_contextual_tag(s, 0, &length, true); /* [0] negoToken */
+ ber_read_octet_string_tag(s, &length); /* OCTET STRING */
+ sspi_SecBufferAlloc(&credssp->negoToken, length);
+ stream_read(s, credssp->negoToken.pvBuffer, length);
+ credssp->negoToken.cbBuffer = length;
+ }
+
+ /* [2] authInfo (OCTET STRING) */
+ if (ber_read_contextual_tag(s, 2, &length, true) != false)
+ {
+ ber_read_octet_string_tag(s, &length); /* OCTET STRING */
+ sspi_SecBufferAlloc(&credssp->authInfo, length);
+ stream_read(s, credssp->authInfo.pvBuffer, length);
+ credssp->authInfo.cbBuffer = length;
+ }
+
+ /* [3] pubKeyAuth (OCTET STRING) */
+ if (ber_read_contextual_tag(s, 3, &length, true) != false)
+ {
+ ber_read_octet_string_tag(s, &length); /* OCTET STRING */
+ sspi_SecBufferAlloc(&credssp->pubKeyAuth, length);
+ stream_read(s, credssp->pubKeyAuth.pvBuffer, length);
+ credssp->pubKeyAuth.cbBuffer = length;
+ }
+
+ stream_free(s);
+
+ return 0;
+}
+
+void credssp_buffer_print(rdpCredssp* credssp)
+{
+ if (credssp->negoToken.cbBuffer > 0)
+ {
+ printf("CredSSP.negoToken (length = %d):\n", (int) credssp->negoToken.cbBuffer);
+ winpr_HexDump(credssp->negoToken.pvBuffer, credssp->negoToken.cbBuffer);
+ }
+
+ if (credssp->pubKeyAuth.cbBuffer > 0)
+ {
+ printf("CredSSP.pubKeyAuth (length = %d):\n", (int) credssp->pubKeyAuth.cbBuffer);
+ winpr_HexDump(credssp->pubKeyAuth.pvBuffer, credssp->pubKeyAuth.cbBuffer);
+ }
+
+ if (credssp->authInfo.cbBuffer > 0)
+ {
+ printf("CredSSP.authInfo (length = %d):\n", (int) credssp->authInfo.cbBuffer);
+ winpr_HexDump(credssp->authInfo.pvBuffer, credssp->authInfo.cbBuffer);
+ }
+}
+
+void credssp_buffer_free(rdpCredssp* credssp)
+{
+ sspi_SecBufferFree(&credssp->negoToken);
+ sspi_SecBufferFree(&credssp->pubKeyAuth);
+ sspi_SecBufferFree(&credssp->authInfo);
+}
+
+/**
+ * Create new CredSSP state machine.
+ * @param transport
+ * @return new CredSSP state machine.
+ */
+
+rdpCredssp* credssp_new(freerdp* instance, rdpTls* tls, rdpSettings* settings)
+{
+ rdpCredssp* credssp;
+
+ credssp = (rdpCredssp*) xzalloc(sizeof(rdpCredssp));
+
+ if (credssp != NULL)
+ {
+ credssp->instance = instance;
+ credssp->settings = settings;
+ credssp->server = settings->server_mode;
+ credssp->tls = tls;
+ credssp->send_seq_num = 0;
+ credssp->recv_seq_num = 0;
+ memset(&credssp->negoToken, 0, sizeof(SecBuffer));
+ memset(&credssp->pubKeyAuth, 0, sizeof(SecBuffer));
+ memset(&credssp->authInfo, 0, sizeof(SecBuffer));
+ }
+
+ return credssp;
+}
+
+/**
+ * Free CredSSP state machine.
+ * @param credssp
+ */
+
+void credssp_free(rdpCredssp* credssp)
+{
+ if (credssp != NULL)
+ {
+ if (credssp->table)
+ credssp->table->DeleteSecurityContext(&credssp->context);
+
+ sspi_SecBufferFree(&credssp->PublicKey);
+ sspi_SecBufferFree(&credssp->ts_credentials);
+
+ free(credssp->identity.User);
+ free(credssp->identity.Domain);
+ free(credssp->identity.Password);
+ free(credssp);
+ }
+}
* limitations under the License.
*/
-#include <time.h>
-
-#ifndef _WIN32
-#include <unistd.h>
-#endif
-
-#include <freerdp/crypto/tls.h>
-
#include <winpr/crt.h>
#include <winpr/sspi.h>
-#include <winpr/print.h>
-#include <winpr/credssp.h>
-
-#include "../sspi.h"
-
-/**
- * TSRequest ::= SEQUENCE {
- * version [0] INTEGER,
- * negoTokens [1] NegoData OPTIONAL,
- * authInfo [2] OCTET STRING OPTIONAL,
- * pubKeyAuth [3] OCTET STRING OPTIONAL
- * }
- *
- * NegoData ::= SEQUENCE OF NegoDataItem
- *
- * NegoDataItem ::= SEQUENCE {
- * negoToken [0] OCTET STRING
- * }
- *
- * TSCredentials ::= SEQUENCE {
- * credType [0] INTEGER,
- * credentials [1] OCTET STRING
- * }
- *
- * TSPasswordCreds ::= SEQUENCE {
- * domainName [0] OCTET STRING,
- * userName [1] OCTET STRING,
- * password [2] OCTET STRING
- * }
- *
- * TSSmartCardCreds ::= SEQUENCE {
- * pin [0] OCTET STRING,
- * cspData [1] TSCspDataDetail,
- * userHint [2] OCTET STRING OPTIONAL,
- * domainHint [3] OCTET STRING OPTIONAL
- * }
- *
- * TSCspDataDetail ::= SEQUENCE {
- * keySpec [0] INTEGER,
- * cardName [1] OCTET STRING OPTIONAL,
- * readerName [2] OCTET STRING OPTIONAL,
- * containerName [3] OCTET STRING OPTIONAL,
- * cspName [4] OCTET STRING OPTIONAL
- * }
- *
- */
-#ifdef WITH_DEBUG_NLA
-#define WITH_DEBUG_CREDSSP
-#endif
-
-/**
- * Initialize NTLMSSP authentication module (client).
- * @param credssp
- */
-
-int credssp_ntlm_client_init(rdpCredssp* credssp)
-{
- freerdp* instance;
- rdpSettings* settings = credssp->settings;
- instance = (freerdp*) settings->instance;
+#include "credssp.h"
- if ((settings->password == NULL) || (settings->username == NULL))
- {
- if (instance->Authenticate)
- {
- boolean proceed = instance->Authenticate(instance,
- &settings->username, &settings->password, &settings->domain);
- if (!proceed)
- return 0;
- }
- }
-
- sspi_SetAuthIdentity(&(credssp->identity), settings->username, settings->domain, settings->password);
-
- sspi_SecBufferAlloc(&credssp->PublicKey, credssp->tls->public_key.length);
- CopyMemory(credssp->PublicKey.pvBuffer, credssp->tls->public_key.data, credssp->tls->public_key.length);
-
- return 1;
-}
-
-/**
- * Initialize NTLMSSP authentication module (server).
- * @param credssp
- */
-
-int credssp_ntlm_server_init(rdpCredssp* credssp)
-{
- freerdp* instance;
- rdpSettings* settings = credssp->settings;
- instance = (freerdp*) settings->instance;
-
- sspi_SetAuthIdentity(&(credssp->identity), "username", NULL, NULL);
-
- sspi_SecBufferAlloc(&credssp->PublicKey, credssp->tls->public_key.length);
- CopyMemory(credssp->PublicKey.pvBuffer, credssp->tls->public_key.data, credssp->tls->public_key.length);
+#include "../sspi.h"
- return 1;
-}
+char* CREDSSP_PACKAGE_NAME = "CredSSP";
-int credssp_client_authenticate(rdpCredssp* credssp)
+SECURITY_STATUS SEC_ENTRY credssp_InitializeSecurityContextW(PCredHandle phCredential, PCtxtHandle phContext,
+ SEC_WCHAR* pszTargetName, ULONG fContextReq, ULONG Reserved1, ULONG TargetDataRep,
+ PSecBufferDesc pInput, ULONG Reserved2, PCtxtHandle phNewContext,
+ PSecBufferDesc pOutput, PULONG pfContextAttr, PTimeStamp ptsExpiry)
{
- ULONG cbMaxToken;
- ULONG fContextReq;
- ULONG pfContextAttr;
- SECURITY_STATUS status;
- CredHandle credentials;
- TimeStamp expiration;
- PSecPkgInfo pPackageInfo;
- PSecBuffer p_buffer;
- SecBuffer input_buffer;
- SecBuffer output_buffer;
- SecBufferDesc input_buffer_desc;
- SecBufferDesc output_buffer_desc;
- boolean have_context;
- boolean have_input_buffer;
- boolean have_pub_key_auth;
-
- sspi_GlobalInit();
-
- if (credssp_ntlm_client_init(credssp) == 0)
- return 0;
-
-#ifdef NATIVE_SSPI
- {
- HMODULE hSSPI;
- INIT_SECURITY_INTERFACE InitSecurityInterface;
- PSecurityFunctionTable pSecurityInterface = NULL;
-
- hSSPI = LoadLibrary(_T("secur32.dll"));
-
-#ifdef UNICODE
- InitSecurityInterface = (INIT_SECURITY_INTERFACE) GetProcAddress(hSSPI, "InitSecurityInterfaceW");
-#else
- InitSecurityInterface = (INIT_SECURITY_INTERFACE) GetProcAddress(hSSPI, "InitSecurityInterfaceA");
-#endif
- credssp->table = (*InitSecurityInterface)();
- }
-#else
- credssp->table = InitSecurityInterface();
-#endif
-
- status = credssp->table->QuerySecurityPackageInfo(NTLMSP_NAME, &pPackageInfo);
-
- if (status != SEC_E_OK)
- {
- printf("QuerySecurityPackageInfo status: 0x%08X\n", status);
- return 0;
- }
-
- cbMaxToken = pPackageInfo->cbMaxToken;
-
- status = credssp->table->AcquireCredentialsHandle(NULL, NTLMSP_NAME,
- SECPKG_CRED_OUTBOUND, NULL, &credssp->identity, NULL, NULL, &credentials, &expiration);
-
- if (status != SEC_E_OK)
- {
- printf("AcquireCredentialsHandle status: 0x%08X\n", status);
- return 0;
- }
-
- have_context = false;
- have_input_buffer = false;
- have_pub_key_auth = false;
- memset(&input_buffer, 0, sizeof(SecBuffer));
- memset(&output_buffer, 0, sizeof(SecBuffer));
- memset(&credssp->ContextSizes, 0, sizeof(SecPkgContext_Sizes));
-
- fContextReq = ISC_REQ_REPLAY_DETECT | ISC_REQ_SEQUENCE_DETECT |
- ISC_REQ_CONFIDENTIALITY | ISC_REQ_DELEGATE;
-
- while (true)
- {
- output_buffer_desc.ulVersion = SECBUFFER_VERSION;
- output_buffer_desc.cBuffers = 1;
- output_buffer_desc.pBuffers = &output_buffer;
- output_buffer.BufferType = SECBUFFER_TOKEN;
- output_buffer.cbBuffer = cbMaxToken;
- output_buffer.pvBuffer = malloc(output_buffer.cbBuffer);
-
- status = credssp->table->InitializeSecurityContext(&credentials,
- (have_context) ? &credssp->context : NULL,
- NULL, fContextReq, 0, SECURITY_NETWORK_DREP,
- (have_input_buffer) ? &input_buffer_desc : NULL,
- 0, &credssp->context, &output_buffer_desc, &pfContextAttr, &expiration);
-
- if (input_buffer.pvBuffer != NULL)
- {
- free(input_buffer.pvBuffer);
- input_buffer.pvBuffer = NULL;
- }
-
- if ((status == SEC_I_COMPLETE_AND_CONTINUE) || (status == SEC_I_COMPLETE_NEEDED) || (status == SEC_E_OK))
- {
- if (credssp->table->CompleteAuthToken != NULL)
- credssp->table->CompleteAuthToken(&credssp->context, &output_buffer_desc);
-
- have_pub_key_auth = true;
-
- if (credssp->table->QueryContextAttributes(&credssp->context, SECPKG_ATTR_SIZES, &credssp->ContextSizes) != SEC_E_OK)
- {
- printf("QueryContextAttributes SECPKG_ATTR_SIZES failure\n");
- return 0;
- }
-
- if (have_pub_key_auth)
- {
- BYTE* p;
- SecBuffer Buffers[2];
- SecBufferDesc Message;
- SECURITY_STATUS encrypt_status;
-
- Buffers[0].BufferType = SECBUFFER_TOKEN; /* Signature */
- Buffers[1].BufferType = SECBUFFER_DATA; /* TLS Public Key */
-
- Buffers[0].cbBuffer = credssp->ContextSizes.cbMaxSignature;
- Buffers[0].pvBuffer = xzalloc(Buffers[0].cbBuffer);
-
- Buffers[1].cbBuffer = credssp->PublicKey.cbBuffer;
- Buffers[1].pvBuffer = malloc(Buffers[1].cbBuffer);
- CopyMemory(Buffers[1].pvBuffer, credssp->PublicKey.pvBuffer, Buffers[1].cbBuffer);
-
- Message.cBuffers = 2;
- Message.ulVersion = SECBUFFER_VERSION;
- Message.pBuffers = (PSecBuffer) &Buffers;
-
- sspi_SecBufferAlloc(&credssp->pubKeyAuth, Buffers[0].cbBuffer + Buffers[1].cbBuffer);
-
- encrypt_status = credssp->table->EncryptMessage(&credssp->context, 0, &Message, 0);
-
- if (encrypt_status != SEC_E_OK)
- {
- printf("EncryptMessage status: 0x%08X\n", encrypt_status);
- return 0;
- }
-
-#ifdef WITH_DEBUG_CREDSSP
- printf("CredSSP.Signature: (%d)\n", (int) Buffers[0].cbBuffer);
- winpr_HexDump((BYTE*) Buffers[0].pvBuffer, Buffers[0].cbBuffer);
- printf("CredSSP.PublicKey: (%d)\n", (int) credssp->PublicKey.cbBuffer);
- winpr_HexDump((BYTE*) credssp->PublicKey.pvBuffer, credssp->PublicKey.cbBuffer);
- printf("CredSSP.PublicKey (encrypted) (%d):\n", (int) Buffers[1].cbBuffer);
- winpr_HexDump((BYTE*) Buffers[1].pvBuffer, Buffers[1].cbBuffer);
-#endif
-
- p = (BYTE*) credssp->pubKeyAuth.pvBuffer;
- CopyMemory(p, Buffers[0].pvBuffer, Buffers[0].cbBuffer); /* Message Signature */
- CopyMemory(&p[Buffers[0].cbBuffer], Buffers[1].pvBuffer, Buffers[1].cbBuffer); /* Encrypted Public Key */
- free(Buffers[0].pvBuffer);
- free(Buffers[1].pvBuffer);
- }
-
- if (status == SEC_I_COMPLETE_NEEDED)
- status = SEC_E_OK;
- else if (status == SEC_I_COMPLETE_AND_CONTINUE)
- status = SEC_I_CONTINUE_NEEDED;
- }
-
- /* send authentication token to server */
-
- if (output_buffer.cbBuffer > 0)
- {
- p_buffer = &output_buffer_desc.pBuffers[0];
-
- credssp->negoToken.pvBuffer = p_buffer->pvBuffer;
- credssp->negoToken.cbBuffer = p_buffer->cbBuffer;
-
-#ifdef WITH_DEBUG_CREDSSP
- printf("Sending Authentication Token\n");
- winpr_HexDump(credssp->negoToken.pvBuffer, credssp->negoToken.cbBuffer);
-#endif
-
- credssp_send(credssp);
- credssp_buffer_free(credssp);
- }
-
- if (status != SEC_I_CONTINUE_NEEDED)
- break;
-
- /* receive server response and place in input buffer */
-
- input_buffer_desc.ulVersion = SECBUFFER_VERSION;
- input_buffer_desc.cBuffers = 1;
- input_buffer_desc.pBuffers = &input_buffer;
- input_buffer.BufferType = SECBUFFER_TOKEN;
-
- if (credssp_recv(credssp) < 0)
- return -1;
-
-#ifdef WITH_DEBUG_CREDSSP
- printf("Receiving Authentication Token\n");
- winpr_HexDump(credssp->negoToken.pvBuffer, credssp->negoToken.cbBuffer);
-#endif
-
- p_buffer = &input_buffer_desc.pBuffers[0];
- p_buffer->pvBuffer = credssp->negoToken.pvBuffer;
- p_buffer->cbBuffer = credssp->negoToken.cbBuffer;
-
- have_input_buffer = true;
- have_context = true;
- }
-
- /* Encrypted Public Key +1 */
- if (credssp_recv(credssp) < 0)
- return -1;
-
- /* Verify Server Public Key Echo */
-
- status = credssp_verify_public_key_echo(credssp);
- credssp_buffer_free(credssp);
-
- if (status != SEC_E_OK)
- return 0;
-
- /* Send encrypted credentials */
-
- status = credssp_encrypt_ts_credentials(credssp);
-
- if (status != SEC_E_OK)
- {
- printf("credssp_encrypt_ts_credentials status: 0x%08X\n", status);
- return 0;
- }
-
- credssp_send(credssp);
- credssp_buffer_free(credssp);
-
- /* Free resources */
-
- credssp->table->FreeCredentialsHandle(&credentials);
- credssp->table->FreeContextBuffer(pPackageInfo);
-
- return 1;
+ return SEC_E_OK;
}
-/**
- * Authenticate with client using CredSSP (server).
- * @param credssp
- * @return 1 if authentication is successful
- */
-
-int credssp_server_authenticate(rdpCredssp* credssp)
+SECURITY_STATUS SEC_ENTRY credssp_InitializeSecurityContextA(PCredHandle phCredential, PCtxtHandle phContext,
+ SEC_CHAR* pszTargetName, ULONG fContextReq, ULONG Reserved1, ULONG TargetDataRep,
+ PSecBufferDesc pInput, ULONG Reserved2, PCtxtHandle phNewContext,
+ PSecBufferDesc pOutput, PULONG pfContextAttr, PTimeStamp ptsExpiry)
{
- UINT32 cbMaxToken;
- ULONG fContextReq;
- ULONG pfContextAttr;
- SECURITY_STATUS status;
- CredHandle credentials;
- TimeStamp expiration;
- PSecPkgInfo pPackageInfo;
- PSecBuffer p_buffer;
- SecBuffer input_buffer;
- SecBuffer output_buffer;
- SecBufferDesc input_buffer_desc;
- SecBufferDesc output_buffer_desc;
- boolean have_context;
- boolean have_input_buffer;
- boolean have_pub_key_auth;
-
- sspi_GlobalInit();
-
- if (credssp_ntlm_server_init(credssp) == 0)
- return 0;
-
-#ifdef NATIVE_SSPI
- {
- HMODULE hSSPI;
- INIT_SECURITY_INTERFACE InitSecurityInterface;
- PSecurityFunctionTable pSecurityInterface = NULL;
-
- hSSPI = LoadLibrary(_T("secur32.dll"));
-
-#ifdef UNICODE
- InitSecurityInterface = (INIT_SECURITY_INTERFACE) GetProcAddress(hSSPI, "InitSecurityInterfaceW");
-#else
- InitSecurityInterface = (INIT_SECURITY_INTERFACE) GetProcAddress(hSSPI, "InitSecurityInterfaceA");
-#endif
- credssp->table = (*InitSecurityInterface)();
- }
-#else
- credssp->table = InitSecurityInterface();
-#endif
-
- status = credssp->table->QuerySecurityPackageInfo(NTLMSP_NAME, &pPackageInfo);
-
- if (status != SEC_E_OK)
- {
- printf("QuerySecurityPackageInfo status: 0x%08X\n", status);
- return 0;
- }
-
- cbMaxToken = pPackageInfo->cbMaxToken;
-
- status = credssp->table->AcquireCredentialsHandle(NULL, NTLMSP_NAME,
- SECPKG_CRED_INBOUND, NULL, &credssp->identity, NULL, NULL, &credentials, &expiration);
-
- if (status != SEC_E_OK)
- {
- printf("AcquireCredentialsHandle status: 0x%08X\n", status);
- return 0;
- }
+ CREDSSP_CONTEXT* context;
+ CREDENTIALS* credentials;
- have_context = false;
- have_input_buffer = false;
- have_pub_key_auth = false;
- memset(&input_buffer, 0, sizeof(SecBuffer));
- memset(&output_buffer, 0, sizeof(SecBuffer));
- memset(&credssp->ContextSizes, 0, sizeof(SecPkgContext_Sizes));
+ context = sspi_SecureHandleGetLowerPointer(phContext);
- fContextReq = ASC_REQ_REPLAY_DETECT | ASC_REQ_SEQUENCE_DETECT |
- ASC_REQ_CONFIDENTIALITY | ASC_REQ_DELEGATE;
-
- while (true)
+ if (!context)
{
- input_buffer_desc.ulVersion = SECBUFFER_VERSION;
- input_buffer_desc.cBuffers = 1;
- input_buffer_desc.pBuffers = &input_buffer;
- input_buffer.BufferType = SECBUFFER_TOKEN;
-
- /* receive authentication token */
-
- input_buffer_desc.ulVersion = SECBUFFER_VERSION;
- input_buffer_desc.cBuffers = 1;
- input_buffer_desc.pBuffers = &input_buffer;
- input_buffer.BufferType = SECBUFFER_TOKEN;
-
- if (credssp_recv(credssp) < 0)
- return -1;
-
-#ifdef WITH_DEBUG_CREDSSP
- printf("Receiving Authentication Token\n");
- credssp_buffer_print(credssp);
-#endif
-
- p_buffer = &input_buffer_desc.pBuffers[0];
- p_buffer->pvBuffer = credssp->negoToken.pvBuffer;
- p_buffer->cbBuffer = credssp->negoToken.cbBuffer;
-
- output_buffer_desc.ulVersion = SECBUFFER_VERSION;
- output_buffer_desc.cBuffers = 1;
- output_buffer_desc.pBuffers = &output_buffer;
- output_buffer.BufferType = SECBUFFER_TOKEN;
- output_buffer.cbBuffer = cbMaxToken;
- output_buffer.pvBuffer = malloc(output_buffer.cbBuffer);
-
- status = credssp->table->AcceptSecurityContext(&credentials,
- have_context? &credssp->context: NULL,
- &input_buffer_desc, fContextReq, SECURITY_NETWORK_DREP, &credssp->context,
- &output_buffer_desc, &pfContextAttr, &expiration);
-
- if (input_buffer.pvBuffer != NULL)
- {
- free(input_buffer.pvBuffer);
- input_buffer.pvBuffer = NULL;
- }
-
- p_buffer = &output_buffer_desc.pBuffers[0];
- credssp->negoToken.pvBuffer = p_buffer->pvBuffer;
- credssp->negoToken.cbBuffer = p_buffer->cbBuffer;
-
- if ((status == SEC_I_COMPLETE_AND_CONTINUE) || (status == SEC_I_COMPLETE_NEEDED))
- {
- if (credssp->table->CompleteAuthToken != NULL)
- credssp->table->CompleteAuthToken(&credssp->context, &output_buffer_desc);
-
- have_pub_key_auth = true;
-
- if (credssp->table->QueryContextAttributes(&credssp->context, SECPKG_ATTR_SIZES, &credssp->ContextSizes) != SEC_E_OK)
- {
- printf("QueryContextAttributes SECPKG_ATTR_SIZES failure\n");
- return 0;
- }
-
- credssp_verify_public_key_echo(credssp);
-
- sspi_SecBufferFree(&credssp->negoToken);
- credssp->negoToken.pvBuffer = NULL;
- credssp->negoToken.cbBuffer = 0;
-
- if (have_pub_key_auth)
- {
- BYTE* p;
- SecBuffer Buffers[2];
- SecBufferDesc Message;
-
- Buffers[0].BufferType = SECBUFFER_DATA; /* TLS Public Key */
- Buffers[1].BufferType = SECBUFFER_TOKEN; /* Signature */
-
- Buffers[0].cbBuffer = credssp->PublicKey.cbBuffer;
- Buffers[0].pvBuffer = malloc(Buffers[0].cbBuffer);
- CopyMemory(Buffers[0].pvBuffer, credssp->PublicKey.pvBuffer, Buffers[0].cbBuffer);
-
- Buffers[1].cbBuffer = credssp->ContextSizes.cbMaxSignature;
- Buffers[1].pvBuffer = xzalloc(Buffers[1].cbBuffer);
-
- Message.cBuffers = 2;
- Message.ulVersion = SECBUFFER_VERSION;
- Message.pBuffers = (PSecBuffer) &Buffers;
+ context = credssp_ContextNew();
- p = (BYTE*) Buffers[0].pvBuffer;
- p[0]++; /* Public Key +1 */
-
- sspi_SecBufferAlloc(&credssp->pubKeyAuth, Buffers[0].cbBuffer + Buffers[1].cbBuffer);
-
- credssp->table->EncryptMessage(&credssp->context, 0, &Message, 0);
-
- p = (BYTE*) credssp->pubKeyAuth.pvBuffer;
- CopyMemory(p, Buffers[1].pvBuffer, Buffers[1].cbBuffer); /* Message Signature */
- CopyMemory(&p[Buffers[1].cbBuffer], Buffers[0].pvBuffer, Buffers[0].cbBuffer); /* Encrypted Public Key */
- }
-
- if (status == SEC_I_COMPLETE_NEEDED)
- status = SEC_E_OK;
- else if (status == SEC_I_COMPLETE_AND_CONTINUE)
- status = SEC_I_CONTINUE_NEEDED;
- }
-
- /* send authentication token */
-
-#ifdef WITH_DEBUG_CREDSSP
- printf("Sending Authentication Token\n");
- credssp_buffer_print(credssp);
-#endif
-
- credssp_send(credssp);
- credssp_buffer_free(credssp);
-
- if (status != SEC_I_CONTINUE_NEEDED)
- break;
-
- have_context = true;
- }
-
- /* Receive encrypted credentials */
-
- if (credssp_recv(credssp) < 0)
- return -1;
-
- credssp_decrypt_ts_credentials(credssp);
-
- if (status != SEC_E_OK)
- {
- printf("AcceptSecurityContext status: 0x%08X\n", status);
- return 0;
- }
-
- status = credssp->table->ImpersonateSecurityContext(&credssp->context);
-
- if (status != SEC_E_OK)
- {
- printf("ImpersonateSecurityContext status: 0x%08X\n", status);
- return 0;
- }
- else
- {
- status = credssp->table->RevertSecurityContext(&credssp->context);
+ credentials = (CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential);
- if (status != SEC_E_OK)
- {
- printf("RevertSecurityContext status: 0x%08X\n", status);
- return 0;
- }
+ sspi_SecureHandleSetLowerPointer(phNewContext, context);
+ sspi_SecureHandleSetUpperPointer(phNewContext, (void*) CREDSSP_PACKAGE_NAME);
}
- credssp->table->FreeContextBuffer(pPackageInfo);
-
- return 1;
-}
-
-/**
- * Authenticate using CredSSP.
- * @param credssp
- * @return 1 if authentication is successful
- */
+ return SEC_E_OK;
-int credssp_authenticate(rdpCredssp* credssp)
-{
- if (credssp->server)
- return credssp_server_authenticate(credssp);
- else
- return credssp_client_authenticate(credssp);
}
-SECURITY_STATUS credssp_verify_public_key_echo(rdpCredssp* credssp)
+CREDSSP_CONTEXT* credssp_ContextNew()
{
- int length;
- ULONG pfQOP;
- BYTE* public_key1;
- BYTE* public_key2;
- BYTE* pub_key_auth;
- int public_key_length;
- SecBuffer Buffers[2];
- SecBufferDesc Message;
- SECURITY_STATUS status;
-
- length = credssp->pubKeyAuth.cbBuffer;
- pub_key_auth = (BYTE*) credssp->pubKeyAuth.pvBuffer;
- public_key_length = credssp->PublicKey.cbBuffer;
+ CREDSSP_CONTEXT* context;
- Buffers[0].BufferType = SECBUFFER_TOKEN; /* Signature */
- Buffers[1].BufferType = SECBUFFER_DATA; /* Encrypted TLS Public Key */
+ context = (CREDSSP_CONTEXT*) calloc(1, sizeof(CREDSSP_CONTEXT));
- Buffers[0].cbBuffer = credssp->ContextSizes.cbMaxSignature;
- Buffers[0].pvBuffer = malloc(Buffers[0].cbBuffer);
- CopyMemory(Buffers[0].pvBuffer, pub_key_auth, Buffers[0].cbBuffer);
-
- Buffers[1].cbBuffer = length - Buffers[0].cbBuffer;
- Buffers[1].pvBuffer = malloc(Buffers[1].cbBuffer);
- CopyMemory(Buffers[1].pvBuffer, &pub_key_auth[Buffers[0].cbBuffer], Buffers[1].cbBuffer);
-
- Message.cBuffers = 2;
- Message.ulVersion = SECBUFFER_VERSION;
- Message.pBuffers = (PSecBuffer) &Buffers;
-
- status = credssp->table->DecryptMessage(&credssp->context, &Message, 0, &pfQOP);
-
- if (status != SEC_E_OK)
- {
- printf("DecryptMessage failure: 0x%08X\n", status);
- return status;
- }
-
- public_key1 = (BYTE*) credssp->PublicKey.pvBuffer;
- public_key2 = (BYTE*) Buffers[1].pvBuffer;
-
- if (!credssp->server)
- public_key2[0]--; /* server echos the public key +1 */
-
- if (memcmp(public_key1, public_key2, public_key_length) != 0)
+ if (context != NULL)
{
- printf("Could not verify server's public key echo\n");
-
- printf("Expected (length = %d):\n", public_key_length);
- winpr_HexDump(public_key1, public_key_length);
- printf("Actual (length = %d):\n", public_key_length);
- winpr_HexDump(public_key2, public_key_length);
-
- return SEC_E_MESSAGE_ALTERED; /* DO NOT SEND CREDENTIALS! */
}
- public_key2[0]++;
-
- free(Buffers[0].pvBuffer);
- free(Buffers[1].pvBuffer);
-
- return SEC_E_OK;
-}
-
-int credssp_skip_ts_password_creds(rdpCredssp* credssp)
-{
- int length;
- int ts_password_creds_length = 0;
-
- length = ber_skip_octet_string(credssp->identity.DomainLength);
- length += ber_skip_contextual_tag(length);
- ts_password_creds_length += length;
-
- length = ber_skip_octet_string(credssp->identity.UserLength);
- length += ber_skip_contextual_tag(length);
- ts_password_creds_length += length;
-
- length = ber_skip_octet_string(credssp->identity.PasswordLength);
- length += ber_skip_contextual_tag(length);
- ts_password_creds_length += length;
-
- length = ber_skip_sequence(ts_password_creds_length);
-
- return length;
-}
-
-void credssp_read_ts_password_creds(rdpCredssp* credssp, STREAM* s)
-{
- int length;
-
- /* TSPasswordCreds (SEQUENCE) */
- ber_read_sequence_tag(s, &length);
-
- /* [0] domainName (OCTET STRING) */
- ber_read_contextual_tag(s, 0, &length, true);
- ber_read_octet_string_tag(s, &length);
- credssp->identity.DomainLength = (UINT32) length;
- credssp->identity.Domain = (UINT16*) malloc(length);
- CopyMemory(credssp->identity.Domain, s->p, credssp->identity.DomainLength);
- stream_seek(s, credssp->identity.DomainLength);
-
- /* [1] userName (OCTET STRING) */
- ber_read_contextual_tag(s, 1, &length, true);
- ber_read_octet_string_tag(s, &length);
- credssp->identity.UserLength = (UINT32) length;
- credssp->identity.User = (UINT16*) malloc(length);
- CopyMemory(credssp->identity.User, s->p, credssp->identity.UserLength);
- stream_seek(s, credssp->identity.UserLength);
-
- /* [2] password (OCTET STRING) */
- ber_read_contextual_tag(s, 2, &length, true);
- ber_read_octet_string_tag(s, &length);
- credssp->identity.PasswordLength = (UINT32) length;
- credssp->identity.Password = (UINT16*) malloc(length);
- CopyMemory(credssp->identity.Password, s->p, credssp->identity.PasswordLength);
- stream_seek(s, credssp->identity.PasswordLength);
+ return context;
}
-void credssp_write_ts_password_creds(rdpCredssp* credssp, STREAM* s)
+void credssp_ContextFree(CREDSSP_CONTEXT* context)
{
- int length;
+ if (!context)
+ return;
- length = credssp_skip_ts_password_creds(credssp);
-
- /* TSPasswordCreds (SEQUENCE) */
- length = ber_get_content_length(length);
- ber_write_sequence_tag(s, length);
-
- /* [0] domainName (OCTET STRING) */
- ber_write_contextual_tag(s, 0, credssp->identity.DomainLength + 2, true);
- ber_write_octet_string(s, (BYTE*) credssp->identity.Domain, credssp->identity.DomainLength);
-
- /* [1] userName (OCTET STRING) */
- ber_write_contextual_tag(s, 1, credssp->identity.UserLength + 2, true);
- ber_write_octet_string(s, (BYTE*) credssp->identity.User, credssp->identity.UserLength);
-
- /* [2] password (OCTET STRING) */
- ber_write_contextual_tag(s, 2, credssp->identity.PasswordLength + 2, true);
- ber_write_octet_string(s, (BYTE*) credssp->identity.Password, credssp->identity.PasswordLength);
-}
-
-int credssp_skip_ts_credentials(rdpCredssp* credssp)
-{
- int length;
- int ts_password_creds_length;
- int ts_credentials_length = 0;
-
- length = ber_skip_integer(0);
- length += ber_skip_contextual_tag(length);
- ts_credentials_length += length;
-
- ts_password_creds_length = credssp_skip_ts_password_creds(credssp);
- length = ber_skip_octet_string(ts_password_creds_length);
- length += ber_skip_contextual_tag(length);
- ts_credentials_length += length;
-
- length = ber_skip_sequence(ts_credentials_length);
-
- return length;
+ free(context);
}
-void credssp_read_ts_credentials(rdpCredssp* credssp, PSecBuffer ts_credentials)
+SECURITY_STATUS SEC_ENTRY credssp_QueryContextAttributes(PCtxtHandle phContext, ULONG ulAttribute, void* pBuffer)
{
- STREAM* s;
- int length;
- int ts_password_creds_length;
-
- s = stream_new(0);
- stream_attach(s, ts_credentials->pvBuffer, ts_credentials->cbBuffer);
-
- /* TSCredentials (SEQUENCE) */
- ber_read_sequence_tag(s, &length);
-
- /* [0] credType (INTEGER) */
- ber_read_contextual_tag(s, 0, &length, true);
- ber_read_integer(s, NULL);
-
- /* [1] credentials (OCTET STRING) */
- ber_read_contextual_tag(s, 1, &length, true);
- ber_read_octet_string_tag(s, &ts_password_creds_length);
+ if (!phContext)
+ return SEC_E_INVALID_HANDLE;
- credssp_read_ts_password_creds(credssp, s);
+ if (!pBuffer)
+ return SEC_E_INSUFFICIENT_MEMORY;
- stream_detach(s);
- stream_free(s);
+ return SEC_E_UNSUPPORTED_FUNCTION;
}
-void credssp_write_ts_credentials(rdpCredssp* credssp, STREAM* s)
+SECURITY_STATUS SEC_ENTRY credssp_AcquireCredentialsHandleW(SEC_WCHAR* pszPrincipal, SEC_WCHAR* pszPackage,
+ ULONG fCredentialUse, PLUID pvLogonID, void* pAuthData, void* pGetKeyFn,
+ void* pvGetKeyArgument, PCredHandle phCredential, PTimeStamp ptsExpiry)
{
- int length;
- int ts_password_creds_length;
-
- length = credssp_skip_ts_credentials(credssp);
- ts_password_creds_length = credssp_skip_ts_password_creds(credssp);
-
- /* TSCredentials (SEQUENCE) */
- length = ber_get_content_length(length);
- length -= ber_write_sequence_tag(s, length);
-
- /* [0] credType (INTEGER) */
- length -= ber_write_contextual_tag(s, 0, 3, true);
- length -= ber_write_integer(s, 1);
-
- /* [1] credentials (OCTET STRING) */
- length -= 1;
- length -= ber_write_contextual_tag(s, 1, length, true);
- length -= ber_write_octet_string_tag(s, ts_password_creds_length);
-
- credssp_write_ts_password_creds(credssp, s);
-}
-
-/**
- * Encode TSCredentials structure.
- * @param credssp
- */
-
-void credssp_encode_ts_credentials(rdpCredssp* credssp)
-{
- STREAM* s;
- int length;
-
- s = stream_new(0);
- length = credssp_skip_ts_credentials(credssp);
- sspi_SecBufferAlloc(&credssp->ts_credentials, length);
- stream_attach(s, credssp->ts_credentials.pvBuffer, length);
-
- credssp_write_ts_credentials(credssp, s);
- stream_detach(s);
- stream_free(s);
-}
-
-SECURITY_STATUS credssp_encrypt_ts_credentials(rdpCredssp* credssp)
-{
- BYTE* p;
- SecBuffer Buffers[2];
- SecBufferDesc Message;
- SECURITY_STATUS status;
-
- credssp_encode_ts_credentials(credssp);
-
- Buffers[0].BufferType = SECBUFFER_TOKEN; /* Signature */
- Buffers[1].BufferType = SECBUFFER_DATA; /* TSCredentials */
-
- Buffers[0].cbBuffer = 16;
- Buffers[0].pvBuffer = xzalloc(Buffers[0].cbBuffer);
-
- Buffers[1].cbBuffer = credssp->ts_credentials.cbBuffer;
- Buffers[1].pvBuffer = malloc(Buffers[1].cbBuffer);
- CopyMemory(Buffers[1].pvBuffer, credssp->ts_credentials.pvBuffer, Buffers[1].cbBuffer);
-
- Message.cBuffers = 2;
- Message.ulVersion = SECBUFFER_VERSION;
- Message.pBuffers = (PSecBuffer) &Buffers;
-
- sspi_SecBufferAlloc(&credssp->authInfo, Buffers[0].cbBuffer + Buffers[1].cbBuffer);
-
- status = credssp->table->EncryptMessage(&credssp->context, 0, &Message, 1);
-
- if (status != SEC_E_OK)
- return status;
-
- p = (BYTE*) credssp->authInfo.pvBuffer;
- CopyMemory(p, Buffers[0].pvBuffer, Buffers[0].cbBuffer); /* Message Signature */
- CopyMemory(&p[Buffers[0].cbBuffer], Buffers[1].pvBuffer, Buffers[1].cbBuffer); /* Encrypted TSCredentials */
-
- free(Buffers[0].pvBuffer);
- free(Buffers[1].pvBuffer);
-
return SEC_E_OK;
}
-SECURITY_STATUS credssp_decrypt_ts_credentials(rdpCredssp* credssp)
+SECURITY_STATUS SEC_ENTRY credssp_AcquireCredentialsHandleA(SEC_CHAR* pszPrincipal, SEC_CHAR* pszPackage,
+ ULONG fCredentialUse, PLUID pvLogonID, void* pAuthData, void* pGetKeyFn,
+ void* pvGetKeyArgument, PCredHandle phCredential, PTimeStamp ptsExpiry)
{
- BYTE* p;
- SecBuffer Buffers[2];
- SecBufferDesc Message;
- SECURITY_STATUS status;
-
- Buffers[0].BufferType = SECBUFFER_TOKEN; /* Signature */
- Buffers[1].BufferType = SECBUFFER_DATA; /* TSCredentials */
-
- Buffers[0].cbBuffer = 16;
- Buffers[0].pvBuffer = malloc(Buffers[0].cbBuffer);
- CopyMemory(Buffers[0].pvBuffer, credssp->authInfo.pvBuffer, Buffers[0].cbBuffer);
+ CREDENTIALS* credentials;
+ SEC_WINNT_AUTH_IDENTITY* identity;
- Buffers[1].cbBuffer = credssp->authInfo.cbBuffer - Buffers[0].cbBuffer;
- Buffers[1].pvBuffer = malloc(Buffers[1].cbBuffer);
- p = (BYTE*) credssp->authInfo.pvBuffer;
- CopyMemory(Buffers[1].pvBuffer, &p[Buffers[0].cbBuffer], Buffers[1].cbBuffer);
-
- Message.cBuffers = 2;
- Message.ulVersion = SECBUFFER_VERSION;
- Message.pBuffers = (PSecBuffer) &Buffers;
-
- sspi_SecBufferAlloc(&credssp->authInfo, Buffers[0].cbBuffer + Buffers[1].cbBuffer);
-
- status = credssp->table->DecryptMessage(&credssp->context, &Message, 1, 0);
+ if (fCredentialUse == SECPKG_CRED_OUTBOUND)
+ {
+ credentials = sspi_CredentialsNew();
+ identity = (SEC_WINNT_AUTH_IDENTITY*) pAuthData;
- if (status != SEC_E_OK)
- return status;
+ CopyMemory(&(credentials->identity), identity, sizeof(SEC_WINNT_AUTH_IDENTITY));
- credssp_read_ts_credentials(credssp, &Buffers[1]);
+ sspi_SecureHandleSetLowerPointer(phCredential, (void*) credentials);
+ sspi_SecureHandleSetUpperPointer(phCredential, (void*) CREDSSP_PACKAGE_NAME);
- free(Buffers[0].pvBuffer);
- free(Buffers[1].pvBuffer);
+ return SEC_E_OK;
+ }
return SEC_E_OK;
}
-int credssp_skip_nego_token(int length)
+SECURITY_STATUS SEC_ENTRY credssp_QueryCredentialsAttributesW(PCredHandle phCredential, ULONG ulAttribute, void* pBuffer)
{
- length = ber_skip_octet_string(length);
- length += ber_skip_contextual_tag(length);
- return length;
-}
-
-int credssp_skip_nego_tokens(int length)
-{
- length = credssp_skip_nego_token(length);
- length += ber_skip_sequence_tag(length);
- length += ber_skip_sequence_tag(length);
- length += ber_skip_contextual_tag(length);
- return length;
-}
-
-int credssp_skip_pub_key_auth(int length)
-{
- length = ber_skip_octet_string(length);
- length += ber_skip_contextual_tag(length);
- return length;
-}
-
-int credssp_skip_auth_info(int length)
-{
- length = ber_skip_octet_string(length);
- length += ber_skip_contextual_tag(length);
- return length;
-}
-
-int credssp_skip_ts_request(int length)
-{
- length += ber_skip_integer(2);
- length += ber_skip_contextual_tag(3);
- length += ber_skip_sequence_tag(length);
- return length;
+ return SEC_E_OK;
}
-/**
- * Send CredSSP message.
- * @param credssp
- */
-
-void credssp_send(rdpCredssp* credssp)
+SECURITY_STATUS SEC_ENTRY credssp_QueryCredentialsAttributesA(PCredHandle phCredential, ULONG ulAttribute, void* pBuffer)
{
- STREAM* s;
- int length;
- int ts_request_length;
- int nego_tokens_length;
- int pub_key_auth_length;
- int auth_info_length;
-
- nego_tokens_length = (credssp->negoToken.cbBuffer > 0) ? credssp_skip_nego_tokens(credssp->negoToken.cbBuffer) : 0;
- pub_key_auth_length = (credssp->pubKeyAuth.cbBuffer > 0) ? credssp_skip_pub_key_auth(credssp->pubKeyAuth.cbBuffer) : 0;
- auth_info_length = (credssp->authInfo.cbBuffer > 0) ? credssp_skip_auth_info(credssp->authInfo.cbBuffer) : 0;
-
- length = nego_tokens_length + pub_key_auth_length + auth_info_length;
- ts_request_length = credssp_skip_ts_request(length);
-
- s = stream_new(ts_request_length);
-
- /* TSRequest */
- length = ber_get_content_length(ts_request_length);
- ber_write_sequence_tag(s, length); /* SEQUENCE */
- ber_write_contextual_tag(s, 0, 3, true); /* [0] version */
- ber_write_integer(s, 2); /* INTEGER */
-
- /* [1] negoTokens (NegoData) */
- if (nego_tokens_length > 0)
+ if (ulAttribute == SECPKG_CRED_ATTR_NAMES)
{
- length = ber_get_content_length(nego_tokens_length);
- length -= ber_write_contextual_tag(s, 1, length, true); /* NegoData */
- length -= ber_write_sequence_tag(s, length); /* SEQUENCE OF NegoDataItem */
- length -= ber_write_sequence_tag(s, length); /* NegoDataItem */
- length -= ber_write_contextual_tag(s, 0, length, true); /* [0] negoToken */
- ber_write_octet_string(s, credssp->negoToken.pvBuffer, length); /* OCTET STRING */
- }
+ CREDENTIALS* credentials;
- /* [2] authInfo (OCTET STRING) */
- if (auth_info_length > 0)
- {
- length = ber_get_content_length(auth_info_length);
- length -= ber_write_contextual_tag(s, 2, length, true);
- ber_write_octet_string(s, credssp->authInfo.pvBuffer, credssp->authInfo.cbBuffer);
- }
+ credentials = (CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential);
- /* [3] pubKeyAuth (OCTET STRING) */
- if (pub_key_auth_length > 0)
- {
- length = ber_get_content_length(pub_key_auth_length);
- length -= ber_write_contextual_tag(s, 3, length, true);
- ber_write_octet_string(s, credssp->pubKeyAuth.pvBuffer, length);
+ return SEC_E_OK;
}
- tls_write(credssp->tls, s->data, stream_get_length(s));
- stream_free(s);
+ return SEC_E_UNSUPPORTED_FUNCTION;
}
-/**
- * Receive CredSSP message.
- * @param credssp
- * @return
- */
-
-int credssp_recv(rdpCredssp* credssp)
+SECURITY_STATUS SEC_ENTRY credssp_FreeCredentialsHandle(PCredHandle phCredential)
{
- STREAM* s;
- int length;
- int status;
- UINT32 version;
-
- s = stream_new(2048);
- status = tls_read(credssp->tls, s->data, stream_get_left(s));
+ CREDENTIALS* credentials;
- if (status < 0)
- {
- stream_free(s) ;
- return -1;
- }
-
- /* TSRequest */
- ber_read_sequence_tag(s, &length);
- ber_read_contextual_tag(s, 0, &length, true);
- ber_read_integer(s, &version);
-
- /* [1] negoTokens (NegoData) */
- if (ber_read_contextual_tag(s, 1, &length, true) != false)
- {
- ber_read_sequence_tag(s, &length); /* SEQUENCE OF NegoDataItem */
- ber_read_sequence_tag(s, &length); /* NegoDataItem */
- ber_read_contextual_tag(s, 0, &length, true); /* [0] negoToken */
- ber_read_octet_string_tag(s, &length); /* OCTET STRING */
- sspi_SecBufferAlloc(&credssp->negoToken, length);
- stream_read(s, credssp->negoToken.pvBuffer, length);
- credssp->negoToken.cbBuffer = length;
- }
+ if (!phCredential)
+ return SEC_E_INVALID_HANDLE;
- /* [2] authInfo (OCTET STRING) */
- if (ber_read_contextual_tag(s, 2, &length, true) != false)
- {
- ber_read_octet_string_tag(s, &length); /* OCTET STRING */
- sspi_SecBufferAlloc(&credssp->authInfo, length);
- stream_read(s, credssp->authInfo.pvBuffer, length);
- credssp->authInfo.cbBuffer = length;
- }
+ credentials = (CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential);
- /* [3] pubKeyAuth (OCTET STRING) */
- if (ber_read_contextual_tag(s, 3, &length, true) != false)
- {
- ber_read_octet_string_tag(s, &length); /* OCTET STRING */
- sspi_SecBufferAlloc(&credssp->pubKeyAuth, length);
- stream_read(s, credssp->pubKeyAuth.pvBuffer, length);
- credssp->pubKeyAuth.cbBuffer = length;
- }
+ if (!credentials)
+ return SEC_E_INVALID_HANDLE;
- stream_free(s);
+ sspi_CredentialsFree(credentials);
- return 0;
+ return SEC_E_OK;
}
-void credssp_buffer_print(rdpCredssp* credssp)
+SECURITY_STATUS SEC_ENTRY credssp_EncryptMessage(PCtxtHandle phContext, ULONG fQOP, PSecBufferDesc pMessage, ULONG MessageSeqNo)
{
- if (credssp->negoToken.cbBuffer > 0)
- {
- printf("CredSSP.negoToken (length = %d):\n", (int) credssp->negoToken.cbBuffer);
- winpr_HexDump(credssp->negoToken.pvBuffer, credssp->negoToken.cbBuffer);
- }
-
- if (credssp->pubKeyAuth.cbBuffer > 0)
- {
- printf("CredSSP.pubKeyAuth (length = %d):\n", (int) credssp->pubKeyAuth.cbBuffer);
- winpr_HexDump(credssp->pubKeyAuth.pvBuffer, credssp->pubKeyAuth.cbBuffer);
- }
-
- if (credssp->authInfo.cbBuffer > 0)
- {
- printf("CredSSP.authInfo (length = %d):\n", (int) credssp->authInfo.cbBuffer);
- winpr_HexDump(credssp->authInfo.pvBuffer, credssp->authInfo.cbBuffer);
- }
+ return SEC_E_OK;
}
-void credssp_buffer_free(rdpCredssp* credssp)
+SECURITY_STATUS SEC_ENTRY credssp_DecryptMessage(PCtxtHandle phContext, PSecBufferDesc pMessage, ULONG MessageSeqNo, ULONG* pfQOP)
{
- sspi_SecBufferFree(&credssp->negoToken);
- sspi_SecBufferFree(&credssp->pubKeyAuth);
- sspi_SecBufferFree(&credssp->authInfo);
+ return SEC_E_OK;
}
-/**
- * Create new CredSSP state machine.
- * @param transport
- * @return new CredSSP state machine.
- */
-
-rdpCredssp* credssp_new(freerdp* instance, rdpTls* tls, rdpSettings* settings)
+SECURITY_STATUS SEC_ENTRY credssp_MakeSignature(PCtxtHandle phContext, ULONG fQOP, PSecBufferDesc pMessage, ULONG MessageSeqNo)
{
- rdpCredssp* credssp;
-
- credssp = (rdpCredssp*) xzalloc(sizeof(rdpCredssp));
-
- if (credssp != NULL)
- {
- credssp->instance = instance;
- credssp->settings = settings;
- credssp->server = settings->server_mode;
- credssp->tls = tls;
- credssp->send_seq_num = 0;
- credssp->recv_seq_num = 0;
- memset(&credssp->negoToken, 0, sizeof(SecBuffer));
- memset(&credssp->pubKeyAuth, 0, sizeof(SecBuffer));
- memset(&credssp->authInfo, 0, sizeof(SecBuffer));
- }
-
- return credssp;
+ return SEC_E_OK;
}
-/**
- * Free CredSSP state machine.
- * @param credssp
- */
-
-void credssp_free(rdpCredssp* credssp)
+SECURITY_STATUS SEC_ENTRY credssp_VerifySignature(PCtxtHandle phContext, PSecBufferDesc pMessage, ULONG MessageSeqNo, ULONG* pfQOP)
{
- if (credssp != NULL)
- {
- if (credssp->table)
- credssp->table->DeleteSecurityContext(&credssp->context);
-
- sspi_SecBufferFree(&credssp->PublicKey);
- sspi_SecBufferFree(&credssp->ts_credentials);
-
- free(credssp->identity.User);
- free(credssp->identity.Domain);
- free(credssp->identity.Password);
- free(credssp);
- }
+ return SEC_E_OK;
}
-/* SSPI */
-
const SecurityFunctionTableA CREDSSP_SecurityFunctionTableA =
{
1, /* dwVersion */
NULL, /* EnumerateSecurityPackages */
- NULL, /* QueryCredentialsAttributes */
- NULL, /* AcquireCredentialsHandle */
- NULL, /* FreeCredentialsHandle */
+ credssp_QueryCredentialsAttributesA, /* QueryCredentialsAttributes */
+ credssp_AcquireCredentialsHandleA, /* AcquireCredentialsHandle */
+ credssp_FreeCredentialsHandle, /* FreeCredentialsHandle */
NULL, /* Reserved2 */
- NULL, /* InitializeSecurityContext */
+ credssp_InitializeSecurityContextA, /* InitializeSecurityContext */
NULL, /* AcceptSecurityContext */
NULL, /* CompleteAuthToken */
NULL, /* DeleteSecurityContext */
NULL, /* ApplyControlToken */
- NULL, /* QueryContextAttributes */
+ credssp_QueryContextAttributes, /* QueryContextAttributes */
NULL, /* ImpersonateSecurityContext */
NULL, /* RevertSecurityContext */
- NULL, /* MakeSignature */
- NULL, /* VerifySignature */
+ credssp_MakeSignature, /* MakeSignature */
+ credssp_VerifySignature, /* VerifySignature */
NULL, /* FreeContextBuffer */
NULL, /* QuerySecurityPackageInfo */
NULL, /* Reserved3 */
NULL, /* AddCredentials */
NULL, /* Reserved8 */
NULL, /* QuerySecurityContextToken */
- NULL, /* EncryptMessage */
- NULL, /* DecryptMessage */
- NULL /* SetContextAttributes */
+ credssp_EncryptMessage, /* EncryptMessage */
+ credssp_DecryptMessage, /* DecryptMessage */
+ NULL, /* SetContextAttributes */
};
const SecurityFunctionTableW CREDSSP_SecurityFunctionTableW =
{
1, /* dwVersion */
NULL, /* EnumerateSecurityPackages */
- NULL, /* QueryCredentialsAttributes */
- NULL, /* AcquireCredentialsHandle */
- NULL, /* FreeCredentialsHandle */
+ credssp_QueryCredentialsAttributesW, /* QueryCredentialsAttributes */
+ credssp_AcquireCredentialsHandleW, /* AcquireCredentialsHandle */
+ credssp_FreeCredentialsHandle, /* FreeCredentialsHandle */
NULL, /* Reserved2 */
- NULL, /* InitializeSecurityContext */
+ credssp_InitializeSecurityContextW, /* InitializeSecurityContext */
NULL, /* AcceptSecurityContext */
NULL, /* CompleteAuthToken */
NULL, /* DeleteSecurityContext */
NULL, /* ApplyControlToken */
- NULL, /* QueryContextAttributes */
+ credssp_QueryContextAttributes, /* QueryContextAttributes */
NULL, /* ImpersonateSecurityContext */
NULL, /* RevertSecurityContext */
- NULL, /* MakeSignature */
- NULL, /* VerifySignature */
+ credssp_MakeSignature, /* MakeSignature */
+ credssp_VerifySignature, /* VerifySignature */
NULL, /* FreeContextBuffer */
NULL, /* QuerySecurityPackageInfo */
NULL, /* Reserved3 */
NULL, /* AddCredentials */
NULL, /* Reserved8 */
NULL, /* QuerySecurityContextToken */
- NULL, /* EncryptMessage */
- NULL, /* DecryptMessage */
- NULL /* SetContextAttributes */
+ credssp_EncryptMessage, /* EncryptMessage */
+ credssp_DecryptMessage, /* DecryptMessage */
+ NULL, /* SetContextAttributes */
};
const SecPkgInfoA CREDSSP_SecPkgInfoA =