static 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) { CREDSSP_CONTEXT* context; SSPI_CREDENTIALS* credentials; context = (CREDSSP_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext); if (!context) { context = credssp_ContextNew(); if (!context) return SEC_E_INSUFFICIENT_MEMORY; credentials = (SSPI_CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential); if (!credentials) { credssp_ContextFree(context); return SEC_E_INVALID_HANDLE; } sspi_SecureHandleSetLowerPointer(phNewContext, context); sspi_SecureHandleSetUpperPointer(phNewContext, (void*) CREDSSP_PACKAGE_NAME); } return SEC_E_OK; }
SECURITY_STATUS SEC_ENTRY schannel_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) { SECURITY_STATUS status; SCHANNEL_CONTEXT* context; SCHANNEL_CREDENTIALS* credentials; context = sspi_SecureHandleGetLowerPointer(phContext); if (!context) { context = schannel_ContextNew(); if (!context) return SEC_E_INSUFFICIENT_MEMORY; credentials = (SCHANNEL_CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential); context->server = FALSE; CopyMemory(&context->cred, &credentials->cred, sizeof(SCHANNEL_CRED)); sspi_SecureHandleSetLowerPointer(phNewContext, context); sspi_SecureHandleSetUpperPointer(phNewContext, (void*) SCHANNEL_PACKAGE_NAME); schannel_openssl_client_init(context->openssl); } status = schannel_openssl_client_process_tokens(context->openssl, pInput, pOutput); return status; }
SECURITY_STATUS SEC_ENTRY schannel_AcceptSecurityContext(PCredHandle phCredential, PCtxtHandle phContext, PSecBufferDesc pInput, ULONG fContextReq, ULONG TargetDataRep, PCtxtHandle phNewContext, PSecBufferDesc pOutput, PULONG pfContextAttr, PTimeStamp ptsTimeStamp) { SECURITY_STATUS status; SCHANNEL_CONTEXT* context; SCHANNEL_CREDENTIALS* credentials; status = SEC_E_OK; context = (SCHANNEL_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext); if (!context) { context = schannel_ContextNew(); if (!context) return SEC_E_INSUFFICIENT_MEMORY; credentials = (SCHANNEL_CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential); context->server = TRUE; sspi_SecureHandleSetLowerPointer(phNewContext, context); sspi_SecureHandleSetUpperPointer(phNewContext, (void*) SCHANNEL_PACKAGE_NAME); schannel_openssl_server_init(context->openssl); } status = schannel_openssl_server_process_tokens(context->openssl, pInput, pOutput); return status; }
SECURITY_STATUS SEC_ENTRY negotiate_AcceptSecurityContext(PCredHandle phCredential, PCtxtHandle phContext, PSecBufferDesc pInput, ULONG fContextReq, ULONG TargetDataRep, PCtxtHandle phNewContext, PSecBufferDesc pOutput, PULONG pfContextAttr, PTimeStamp ptsTimeStamp) { SECURITY_STATUS status; NEGOTIATE_CONTEXT* context; context = (NEGOTIATE_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext); if (!context) { context = negotiate_ContextNew(); if (!context) return SEC_E_INTERNAL_ERROR; sspi_SecureHandleSetLowerPointer(phNewContext, context); sspi_SecureHandleSetUpperPointer(phNewContext, (void*) NEGOTIATE_PACKAGE_NAME); } status = context->sspiA->AcceptSecurityContext(phCredential, &(context->SubContext), pInput, fContextReq, TargetDataRep, &(context->SubContext), pOutput, pfContextAttr, ptsTimeStamp); if (status != SEC_E_OK) { WLog_WARN(TAG, "AcceptSecurityContext status %s [%08X]", GetSecurityStatusString(status), status); } return status; }
SECURITY_STATUS SEC_ENTRY negotiate_AcceptSecurityContext(PCredHandle phCredential, PCtxtHandle phContext, PSecBufferDesc pInput, ULONG fContextReq, ULONG TargetDataRep, PCtxtHandle phNewContext, PSecBufferDesc pOutput, PULONG pfContextAttr, PTimeStamp ptsTimeStamp) { SECURITY_STATUS status; NEGOTIATE_CONTEXT* context; context = (NEGOTIATE_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext); if (!context) { context = negotiate_ContextNew(); if (!context) return SEC_E_INTERNAL_ERROR; sspi_SecureHandleSetLowerPointer(phNewContext, context); sspi_SecureHandleSetUpperPointer(phNewContext, (void*) NEGO_SSP_NAME); } negotiate_SetSubPackage(context, (const char*) NTLM_SSP_NAME); /* server-side Kerberos not yet implemented */ status = context->sspiA->AcceptSecurityContext(phCredential, &(context->SubContext), pInput, fContextReq, TargetDataRep, &(context->SubContext), pOutput, pfContextAttr, ptsTimeStamp); if (status != SEC_E_OK) { WLog_WARN(TAG, "AcceptSecurityContext status %s [0x%08"PRIX32"]", GetSecurityStatusString(status), status); } return status; }
SECURITY_STATUS SEC_ENTRY ntlm_SetContextAttributesW(PCtxtHandle phContext, ULONG ulAttribute, void* pBuffer, ULONG cbBuffer) { NTLM_CONTEXT* context; if (!phContext) return SEC_E_INVALID_HANDLE; if (!pBuffer) return SEC_E_INVALID_PARAMETER; context = (NTLM_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext); if (ulAttribute == SECPKG_ATTR_AUTH_NTLM_HASH) { SecPkgContext_AuthNtlmHash* AuthNtlmHash = (SecPkgContext_AuthNtlmHash*) pBuffer; if (cbBuffer < sizeof(SecPkgContext_AuthNtlmHash)) return SEC_E_INVALID_PARAMETER; CopyMemory(context->NtlmHash, AuthNtlmHash->NtlmHash, 16); return SEC_E_OK; } return SEC_E_UNSUPPORTED_FUNCTION; }
SECURITY_STATUS SEC_ENTRY negotiate_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) { SECURITY_STATUS status; NEGOTIATE_CONTEXT* context; context = (NEGOTIATE_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext); if (!context) { context = negotiate_ContextNew(); if (!context) return SEC_E_INTERNAL_ERROR; sspi_SecureHandleSetLowerPointer(phNewContext, context); sspi_SecureHandleSetUpperPointer(phNewContext, (void*) NEGOTIATE_PACKAGE_NAME); } status = context->sspiA->InitializeSecurityContextA(phCredential, &(context->SubContext), pszTargetName, fContextReq, Reserved1, TargetDataRep, pInput, Reserved2, &(context->SubContext), pOutput, pfContextAttr, ptsExpiry); return status; }
SECURITY_STATUS SEC_ENTRY ntlm_QueryContextAttributesW(PCtxtHandle phContext, ULONG ulAttribute, void* pBuffer) { NTLM_CONTEXT* context; if (!phContext) return SEC_E_INVALID_HANDLE; if (!pBuffer) return SEC_E_INSUFFICIENT_MEMORY; context = (NTLM_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext); if (ulAttribute == SECPKG_ATTR_SIZES) { SecPkgContext_Sizes* ContextSizes = (SecPkgContext_Sizes*) pBuffer; ContextSizes->cbMaxToken = 2010; ContextSizes->cbMaxSignature = 16; ContextSizes->cbBlockSize = 0; ContextSizes->cbSecurityTrailer = 16; return SEC_E_OK; } else if (ulAttribute == SECPKG_ATTR_AUTH_IDENTITY) { int status; char* UserA = NULL; char* DomainA = NULL; SSPI_CREDENTIALS* credentials; SecPkgContext_AuthIdentity* AuthIdentity = (SecPkgContext_AuthIdentity*) pBuffer; context->UseSamFileDatabase = FALSE; credentials = context->credentials; ZeroMemory(AuthIdentity, sizeof(SecPkgContext_AuthIdentity)); UserA = AuthIdentity->User; status = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) credentials->identity.User, credentials->identity.UserLength, &UserA, 256, NULL, NULL); if (status <= 0) return SEC_E_INTERNAL_ERROR; DomainA = AuthIdentity->Domain; status = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) credentials->identity.Domain, credentials->identity.DomainLength, &DomainA, 256, NULL, NULL); if (status <= 0) return SEC_E_INTERNAL_ERROR; return SEC_E_OK; } return SEC_E_UNSUPPORTED_FUNCTION; }
SECURITY_STATUS SEC_ENTRY negotiate_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) { SECURITY_STATUS status; NEGOTIATE_CONTEXT* context; context = (NEGOTIATE_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext); if (!context) { context = negotiate_ContextNew(); if (!context) return SEC_E_INTERNAL_ERROR; sspi_SecureHandleSetLowerPointer(phNewContext, context); sspi_SecureHandleSetUpperPointer(phNewContext, (void*) NEGO_SSP_NAME); } /* if Kerberos has previously failed or WITH_GSSAPI is not defined, we use NTLM directly */ if (ErrorInitContextKerberos == FALSE) { if (!pInput) { negotiate_SetSubPackage(context, (const char*) KERBEROS_SSP_NAME); } status = context->sspiA->InitializeSecurityContextA(phCredential, &(context->SubContext), pszTargetName, fContextReq, Reserved1, TargetDataRep, pInput, Reserved2, &(context->SubContext), pOutput, pfContextAttr, ptsExpiry); if (status == SEC_E_NO_CREDENTIALS) { WLog_WARN(TAG, "No Kerberos credentials. Retry with NTLM"); ErrorInitContextKerberos = TRUE; context->sspiA->DeleteSecurityContext(&(context->SubContext)); negotiate_ContextFree(context); return status; } } else { if (!pInput) { context->sspiA->DeleteSecurityContext(&(context->SubContext)); negotiate_SetSubPackage(context, (const char*) NTLM_SSP_NAME); } status = context->sspiA->InitializeSecurityContextA(phCredential, &(context->SubContext), pszTargetName, fContextReq, Reserved1, TargetDataRep, pInput, Reserved2, &(context->SubContext), pOutput, pfContextAttr, ptsExpiry); } return status; }
SECURITY_STATUS SEC_ENTRY negotiate_InitializeSecurityContextA(PCredHandle phCredential, PCtxtHandle phContext, SEC_CHAR* pszTargetName, uint32 fContextReq, uint32 Reserved1, uint32 TargetDataRep, PSecBufferDesc pInput, uint32 Reserved2, PCtxtHandle phNewContext, PSecBufferDesc pOutput, uint32* pfContextAttr, PTimeStamp ptsExpiry) { NEGOTIATE_CONTEXT* context; //SECURITY_STATUS status; CREDENTIALS* credentials; //PSecBuffer input_SecBuffer; PSecBuffer output_SecBuffer; //KrbTGTREQ krb_tgtreq; context = sspi_SecureHandleGetLowerPointer(phContext); if (!context) { context = negotiate_ContextNew(); credentials = (CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential); negotiate_SetContextIdentity(context, &credentials->identity); sspi_SecureHandleSetLowerPointer(phNewContext, context); sspi_SecureHandleSetUpperPointer(phNewContext, (void*) NEGOTIATE_PACKAGE_NAME); } if((!pInput) && (context->state == NEGOTIATE_STATE_INITIAL)) { if (!pOutput) return SEC_E_INVALID_TOKEN; if (pOutput->cBuffers < 1) return SEC_E_INVALID_TOKEN; output_SecBuffer = &pOutput->pBuffers[0]; if (output_SecBuffer->cbBuffer < 1) return SEC_E_INSUFFICIENT_MEMORY; } return SEC_E_OK; }
SECURITY_STATUS SEC_ENTRY ntlm_DeleteSecurityContext(PCtxtHandle phContext) { NTLM_CONTEXT* context; context = (NTLM_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext); if (!context) return SEC_E_INVALID_HANDLE; ntlm_ContextFree(context); return SEC_E_OK; }
SECURITY_STATUS SEC_ENTRY negotiate_VerifySignature(PCtxtHandle phContext, PSecBufferDesc pMessage, ULONG MessageSeqNo, ULONG* pfQOP) { NEGOTIATE_CONTEXT* context; SECURITY_STATUS status = SEC_E_UNSUPPORTED_FUNCTION; context = (NEGOTIATE_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext); if (context->sspiW->VerifySignature) status = context->sspiW->VerifySignature(&(context->SubContext), pMessage, MessageSeqNo, pfQOP); return status; }
SECURITY_STATUS SEC_ENTRY schannel_DeleteSecurityContext(PCtxtHandle phContext) { SCHANNEL_CONTEXT* context; context = (SCHANNEL_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext); if (!context) return SEC_E_INVALID_HANDLE; schannel_ContextFree(context); return SEC_E_OK; }
SECURITY_STATUS SEC_ENTRY schannel_QueryCredentialsAttributesA(PCredHandle phCredential, ULONG ulAttribute, void* pBuffer) { if (ulAttribute == SECPKG_CRED_ATTR_NAMES) { CREDENTIALS* credentials; credentials = (CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential); return SEC_E_OK; } return SEC_E_UNSUPPORTED_FUNCTION; }
SECURITY_STATUS SEC_ENTRY kerberos_InitializeSecurityContextA(PCredHandle phCredential, PCtxtHandle phContext, SEC_CHAR* pszTargetName, uint32 fContextReq, uint32 Reserved1, uint32 TargetDataRep, PSecBufferDesc pInput, uint32 Reserved2, PCtxtHandle phNewContext, PSecBufferDesc pOutput, uint32* pfContextAttr, PTimeStamp ptsExpiry) { KRB_CONTEXT* krb_ctx; //SECURITY_STATUS status; //CREDENTIALS* credentials; //PSecBuffer input_SecBuffer; //PSecBuffer output_SecBuffer; int errcode; errcode = 0; krb_ctx = (KRB_CONTEXT*)sspi_SecureHandleGetLowerPointer(phContext); if (!krb_ctx) return SEC_E_INVALID_HANDLE; else { while(true) { switch(krb_ctx->state) { case KRB_PACKET_ERROR: kerberos_ContextFree(krb_ctx); return SEC_E_INVALID_HANDLE; break; case KRB_STATE_INITIAL: case KRB_ASREP_ERR: krb_asreq_send(krb_ctx, errcode); break; case KRB_ASREQ_OK: errcode = krb_asrep_recv(krb_ctx); break; case KRB_ASREP_OK: krb_tgsreq_send(krb_ctx, 0); break; case KRB_TGSREQ_OK: krb_tgsrep_recv(krb_ctx); break; case KRB_TGSREP_OK: return SEC_I_COMPLETE_AND_CONTINUE; break; default: printf("not implemented\n"); return -1; } } } }
SECURITY_STATUS SEC_ENTRY negotiate_RevertSecurityContext(PCtxtHandle phContext) { NEGOTIATE_CONTEXT* context; SECURITY_STATUS status = SEC_E_OK; context = (NEGOTIATE_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext); if (!phContext) return SEC_E_INVALID_HANDLE; if (context->sspiW->RevertSecurityContext) status = context->sspiW->RevertSecurityContext(&(context->SubContext)); return status; }
SECURITY_STATUS SEC_ENTRY negotiate_CompleteAuthToken(PCtxtHandle phContext, PSecBufferDesc pToken) { NEGOTIATE_CONTEXT* context; SECURITY_STATUS status = SEC_E_OK; context = (NEGOTIATE_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext); if (!context) return SEC_E_INVALID_HANDLE; if (context->sspiW->CompleteAuthToken) status = context->sspiW->CompleteAuthToken(&(context->SubContext), pToken); return status; }
SECURITY_STATUS SEC_ENTRY schannel_EncryptMessage(PCtxtHandle phContext, ULONG fQOP, PSecBufferDesc pMessage, ULONG MessageSeqNo) { SECURITY_STATUS status; SCHANNEL_CONTEXT* context; context = (SCHANNEL_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext); if (!context) return SEC_E_INVALID_HANDLE; status = schannel_openssl_encrypt_message(context->openssl, pMessage); return status; }
SECURITY_STATUS SEC_ENTRY schannel_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) { SCHANNEL_CONTEXT* context; CREDENTIALS* credentials; context = sspi_SecureHandleGetLowerPointer(phContext); if (!context) { context = schannel_ContextNew(); credentials = (CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential); sspi_SecureHandleSetLowerPointer(phNewContext, context); sspi_SecureHandleSetUpperPointer(phNewContext, (void*) SCHANNEL_PACKAGE_NAME); } return SEC_E_OK; }
SECURITY_STATUS SEC_ENTRY ntlm_FreeCredentialsHandle(PCredHandle phCredential) { SSPI_CREDENTIALS* credentials; if (!phCredential) return SEC_E_INVALID_HANDLE; credentials = (SSPI_CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential); if (!credentials) return SEC_E_INVALID_HANDLE; sspi_CredentialsFree(credentials); return SEC_E_OK; }
static SECURITY_STATUS SEC_ENTRY credssp_QueryCredentialsAttributesA(PCredHandle phCredential, ULONG ulAttribute, void* pBuffer) { if (ulAttribute == SECPKG_CRED_ATTR_NAMES) { SSPI_CREDENTIALS* credentials = (SSPI_CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential); if (!credentials) return SEC_E_INVALID_HANDLE; return SEC_E_OK; } return SEC_E_UNSUPPORTED_FUNCTION; }
SECURITY_STATUS SEC_ENTRY ntlm_CompleteAuthToken(PCtxtHandle phContext, PSecBufferDesc pToken) { NTLM_CONTEXT* context; SECURITY_STATUS status = SEC_E_OK; context = (NTLM_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext); if (!context) return SEC_E_INVALID_HANDLE; if (context->server) { status = ntlm_server_AuthenticateComplete(context); } return status; }
SECURITY_STATUS ntlm_QueryCredentialsAttributes(CRED_HANDLE* phCredential, uint32 ulAttribute, void* pBuffer) { if (ulAttribute == SECPKG_CRED_ATTR_NAMES) { CREDENTIALS* credentials; SEC_PKG_CREDENTIALS_NAMES* credential_names = (SEC_PKG_CREDENTIALS_NAMES*) pBuffer; credentials = (CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential); if (credentials->identity.Flags == SEC_AUTH_IDENTITY_ANSI) credential_names->sUserName = xstrdup((char*) credentials->identity.User); return SEC_E_OK; } return SEC_E_UNSUPPORTED_FUNCTION; }
SECURITY_STATUS SEC_ENTRY negotiate_QueryCredentialsAttributesA(PCredHandle phCredential, uint32 ulAttribute, void* pBuffer) { if (ulAttribute == SECPKG_CRED_ATTR_NAMES) { CREDENTIALS* credentials; //SecPkgCredentials_Names* credential_names = (SecPkgCredentials_Names*) pBuffer; credentials = (CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential); //if (credentials->identity.Flags == SEC_WINNT_AUTH_IDENTITY_ANSI) // credential_names->sUserName = xstrdup((char*) credentials->identity.User); return SEC_E_OK; } return SEC_E_UNSUPPORTED_FUNCTION; }
SECURITY_STATUS SEC_ENTRY negotiate_SetContextAttributesA(PCtxtHandle phContext, ULONG ulAttribute, void* pBuffer, ULONG cbBuffer) { NEGOTIATE_CONTEXT* context; SECURITY_STATUS status = SEC_E_OK; context = (NEGOTIATE_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext); if (!phContext) return SEC_E_INVALID_HANDLE; if (!pBuffer) return SEC_E_INSUFFICIENT_MEMORY; if (context->sspiA->SetContextAttributesA) status = context->sspiA->SetContextAttributesA(&(context->SubContext), ulAttribute, pBuffer, cbBuffer); return status; }
SECURITY_STATUS SEC_ENTRY ntlm_DecryptMessage(PCtxtHandle phContext, PSecBufferDesc pMessage, ULONG MessageSeqNo, PULONG pfQOP) { int index; int length; void* data; UINT32 SeqNo; HMAC_CTX hmac; BYTE digest[16]; BYTE checksum[8]; UINT32 version = 1; NTLM_CONTEXT* context; BYTE expected_signature[16]; PSecBuffer data_buffer = NULL; PSecBuffer signature_buffer = NULL; SeqNo = (UINT32) MessageSeqNo; context = (NTLM_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext); for (index = 0; index < (int) pMessage->cBuffers; index++) { if (pMessage->pBuffers[index].BufferType == SECBUFFER_DATA) data_buffer = &pMessage->pBuffers[index]; else if (pMessage->pBuffers[index].BufferType == SECBUFFER_TOKEN) signature_buffer = &pMessage->pBuffers[index]; } if (!data_buffer) return SEC_E_INVALID_TOKEN; if (!signature_buffer) return SEC_E_INVALID_TOKEN; /* Copy original data buffer */ length = data_buffer->cbBuffer; data = malloc(length); if (!data) return SEC_E_INSUFFICIENT_MEMORY; CopyMemory(data, data_buffer->pvBuffer, length); /* Decrypt message using with RC4, result overwrites original buffer */ if (context->confidentiality) RC4(&context->RecvRc4Seal, length, (BYTE*) data, (BYTE*) data_buffer->pvBuffer); else CopyMemory(data_buffer->pvBuffer, data, length); /* Compute the HMAC-MD5 hash of ConcatenationOf(seq_num,data) using the client signing key */ HMAC_CTX_init(&hmac); HMAC_Init_ex(&hmac, context->RecvSigningKey, 16, EVP_md5(), NULL); HMAC_Update(&hmac, (void*) &(SeqNo), 4); HMAC_Update(&hmac, (void*) data_buffer->pvBuffer, data_buffer->cbBuffer); HMAC_Final(&hmac, digest, NULL); HMAC_CTX_cleanup(&hmac); #ifdef WITH_DEBUG_NTLM fprintf(stderr, "Encrypted Data Buffer (length = %d)\n", length); winpr_HexDump(data, length); fprintf(stderr, "\n"); fprintf(stderr, "Data Buffer (length = %d)\n", (int) data_buffer->cbBuffer); winpr_HexDump(data_buffer->pvBuffer, data_buffer->cbBuffer); fprintf(stderr, "\n"); #endif free(data); /* RC4-encrypt first 8 bytes of digest */ RC4(&context->RecvRc4Seal, 8, digest, checksum); /* Concatenate version, ciphertext and sequence number to build signature */ CopyMemory(expected_signature, (void*) &version, 4); CopyMemory(&expected_signature[4], (void*) checksum, 8); CopyMemory(&expected_signature[12], (void*) &(SeqNo), 4); context->RecvSeqNum++; if (memcmp(signature_buffer->pvBuffer, expected_signature, 16) != 0) { /* signature verification failed! */ fprintf(stderr, "signature verification failed, something nasty is going on!\n"); fprintf(stderr, "Expected Signature:\n"); winpr_HexDump(expected_signature, 16); fprintf(stderr, "Actual Signature:\n"); winpr_HexDump((BYTE*) signature_buffer->pvBuffer, 16); return SEC_E_MESSAGE_ALTERED; } return SEC_E_OK; }
SECURITY_STATUS SEC_ENTRY ntlm_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) { NTLM_CONTEXT* context; SECURITY_STATUS status; SSPI_CREDENTIALS* credentials; PSecBuffer input_buffer = NULL; PSecBuffer output_buffer = NULL; PSecBuffer channel_bindings = NULL; context = (NTLM_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext); if (!context) { context = ntlm_ContextNew(); if (!context) return SEC_E_INSUFFICIENT_MEMORY; if (fContextReq & ISC_REQ_CONFIDENTIALITY) context->confidentiality = TRUE; credentials = (SSPI_CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential); context->credentials = credentials; if (context->Workstation.Length < 1) { if (ntlm_SetContextWorkstation(context, NULL) < 0) return SEC_E_INTERNAL_ERROR; } if (ntlm_SetContextServicePrincipalNameW(context, pszTargetName) < 0) return SEC_E_INTERNAL_ERROR; sspi_SecureHandleSetLowerPointer(phNewContext, context); sspi_SecureHandleSetUpperPointer(phNewContext, (void*) NTLM_PACKAGE_NAME); } if ((!pInput) || (context->state == NTLM_STATE_AUTHENTICATE)) { if (!pOutput) return SEC_E_INVALID_TOKEN; if (pOutput->cBuffers < 1) return SEC_E_INVALID_TOKEN; output_buffer = sspi_FindSecBuffer(pOutput, SECBUFFER_TOKEN); if (!output_buffer) return SEC_E_INVALID_TOKEN; if (output_buffer->cbBuffer < 1) return SEC_E_INVALID_TOKEN; if (context->state == NTLM_STATE_INITIAL) context->state = NTLM_STATE_NEGOTIATE; if (context->state == NTLM_STATE_NEGOTIATE) return ntlm_write_NegotiateMessage(context, output_buffer); return SEC_E_OUT_OF_SEQUENCE; } else { if (pInput->cBuffers < 1) return SEC_E_INVALID_TOKEN; input_buffer = sspi_FindSecBuffer(pInput, SECBUFFER_TOKEN); if (!input_buffer) return SEC_E_INVALID_TOKEN; if (input_buffer->cbBuffer < 1) return SEC_E_INVALID_TOKEN; channel_bindings = sspi_FindSecBuffer(pInput, SECBUFFER_CHANNEL_BINDINGS); if (channel_bindings) { context->Bindings.BindingsLength = channel_bindings->cbBuffer; context->Bindings.Bindings = (SEC_CHANNEL_BINDINGS*) channel_bindings->pvBuffer; } if (context->state == NTLM_STATE_CHALLENGE) { status = ntlm_read_ChallengeMessage(context, input_buffer); if (!pOutput) return SEC_E_INVALID_TOKEN; if (pOutput->cBuffers < 1) return SEC_E_INVALID_TOKEN; output_buffer = sspi_FindSecBuffer(pOutput, SECBUFFER_TOKEN); if (!output_buffer) return SEC_E_INVALID_TOKEN; if (output_buffer->cbBuffer < 1) return SEC_E_INSUFFICIENT_MEMORY; if (context->state == NTLM_STATE_AUTHENTICATE) return ntlm_write_AuthenticateMessage(context, output_buffer); } return SEC_E_OUT_OF_SEQUENCE; } return SEC_E_OUT_OF_SEQUENCE; }
/** * @see http://msdn.microsoft.com/en-us/library/windows/desktop/aa374707 */ SECURITY_STATUS SEC_ENTRY ntlm_AcceptSecurityContext(PCredHandle phCredential, PCtxtHandle phContext, PSecBufferDesc pInput, ULONG fContextReq, ULONG TargetDataRep, PCtxtHandle phNewContext, PSecBufferDesc pOutput, PULONG pfContextAttr, PTimeStamp ptsTimeStamp) { NTLM_CONTEXT* context; SECURITY_STATUS status; SSPI_CREDENTIALS* credentials; PSecBuffer input_buffer; PSecBuffer output_buffer; context = (NTLM_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext); if (!context) { context = ntlm_ContextNew(); if (!context) return SEC_E_INSUFFICIENT_MEMORY; context->server = TRUE; if (fContextReq & ASC_REQ_CONFIDENTIALITY) context->confidentiality = TRUE; credentials = (SSPI_CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential); context->credentials = credentials; ntlm_SetContextTargetName(context, NULL); sspi_SecureHandleSetLowerPointer(phNewContext, context); sspi_SecureHandleSetUpperPointer(phNewContext, (void*) NTLM_PACKAGE_NAME); } if (context->state == NTLM_STATE_INITIAL) { context->state = NTLM_STATE_NEGOTIATE; if (!pInput) return SEC_E_INVALID_TOKEN; if (pInput->cBuffers < 1) return SEC_E_INVALID_TOKEN; input_buffer = sspi_FindSecBuffer(pInput, SECBUFFER_TOKEN); if (!input_buffer) return SEC_E_INVALID_TOKEN; if (input_buffer->cbBuffer < 1) return SEC_E_INVALID_TOKEN; status = ntlm_read_NegotiateMessage(context, input_buffer); if (context->state == NTLM_STATE_CHALLENGE) { if (!pOutput) return SEC_E_INVALID_TOKEN; if (pOutput->cBuffers < 1) return SEC_E_INVALID_TOKEN; output_buffer = sspi_FindSecBuffer(pOutput, SECBUFFER_TOKEN); if (!output_buffer->BufferType) return SEC_E_INVALID_TOKEN; if (output_buffer->cbBuffer < 1) return SEC_E_INSUFFICIENT_MEMORY; return ntlm_write_ChallengeMessage(context, output_buffer); } return SEC_E_OUT_OF_SEQUENCE; } else if (context->state == NTLM_STATE_AUTHENTICATE) { if (!pInput) return SEC_E_INVALID_TOKEN; if (pInput->cBuffers < 1) return SEC_E_INVALID_TOKEN; input_buffer = sspi_FindSecBuffer(pInput, SECBUFFER_TOKEN); if (!input_buffer) return SEC_E_INVALID_TOKEN; if (input_buffer->cbBuffer < 1) return SEC_E_INVALID_TOKEN; status = ntlm_read_AuthenticateMessage(context, input_buffer); if (pOutput) { ULONG i; for (i = 0; i < pOutput->cBuffers; i++) { pOutput->pBuffers[i].cbBuffer = 0; pOutput->pBuffers[i].BufferType = SECBUFFER_TOKEN; } } return status; } return SEC_E_OUT_OF_SEQUENCE; }
SECURITY_STATUS SEC_ENTRY ntlm_DecryptMessage(PCtxtHandle phContext, PSecBufferDesc pMessage, uint32 MessageSeqNo, uint32* pfQOP) { int index; int length; void* data; HMAC_CTX hmac; uint8 digest[16]; uint8 checksum[8]; uint32 version = 1; NTLM_CONTEXT* context; uint8 expected_signature[16]; PSecBuffer data_buffer = NULL; PSecBuffer signature_buffer = NULL; context = sspi_SecureHandleGetLowerPointer(phContext); for (index = 0; index < (int) pMessage->cBuffers; index++) { if (pMessage->pBuffers[index].BufferType == SECBUFFER_DATA) data_buffer = &pMessage->pBuffers[index]; else if (pMessage->pBuffers[index].BufferType == SECBUFFER_TOKEN) signature_buffer = &pMessage->pBuffers[index]; } if (!data_buffer) return SEC_E_INVALID_TOKEN; if (!signature_buffer) return SEC_E_INVALID_TOKEN; /* Copy original data buffer */ length = data_buffer->cbBuffer; data = xmalloc(length); memcpy(data, data_buffer->pvBuffer, length); /* Decrypt message using with RC4 */ crypto_rc4(context->RecvRc4Seal, length, data, data_buffer->pvBuffer); /* Compute the HMAC-MD5 hash of ConcatenationOf(seq_num,data) using the client signing key */ HMAC_CTX_init(&hmac); HMAC_Init_ex(&hmac, context->RecvSigningKey, 16, EVP_md5(), NULL); HMAC_Update(&hmac, (void*) &(MessageSeqNo), 4); HMAC_Update(&hmac, data_buffer->pvBuffer, data_buffer->cbBuffer); HMAC_Final(&hmac, digest, NULL); HMAC_CTX_cleanup(&hmac); xfree(data); /* RC4-encrypt first 8 bytes of digest */ crypto_rc4(context->RecvRc4Seal, 8, digest, checksum); /* Concatenate version, ciphertext and sequence number to build signature */ memcpy(expected_signature, (void*) &version, 4); memcpy(&expected_signature[4], (void*) checksum, 8); memcpy(&expected_signature[12], (void*) &(MessageSeqNo), 4); context->RecvSeqNum++; if (memcmp(signature_buffer->pvBuffer, expected_signature, 16) != 0) { /* signature verification failed! */ printf("signature verification failed, something nasty is going on!\n"); return SEC_E_MESSAGE_ALTERED; } return SEC_E_OK; }
SECURITY_STATUS SEC_ENTRY ntlm_EncryptMessage(PCtxtHandle phContext, uint32 fQOP, PSecBufferDesc pMessage, uint32 MessageSeqNo) { int index; int length; void* data; HMAC_CTX hmac; uint8 digest[16]; uint8 checksum[8]; uint8* signature; uint32 version = 1; NTLM_CONTEXT* context; PSecBuffer data_buffer = NULL; PSecBuffer signature_buffer = NULL; context = sspi_SecureHandleGetLowerPointer(phContext); for (index = 0; index < (int) pMessage->cBuffers; index++) { if (pMessage->pBuffers[index].BufferType == SECBUFFER_DATA) data_buffer = &pMessage->pBuffers[index]; else if (pMessage->pBuffers[index].BufferType == SECBUFFER_TOKEN) signature_buffer = &pMessage->pBuffers[index]; } if (!data_buffer) return SEC_E_INVALID_TOKEN; if (!signature_buffer) return SEC_E_INVALID_TOKEN; /* Copy original data buffer */ length = data_buffer->cbBuffer; data = xmalloc(length); memcpy(data, data_buffer->pvBuffer, length); /* Compute the HMAC-MD5 hash of ConcatenationOf(seq_num,data) using the client signing key */ HMAC_CTX_init(&hmac); HMAC_Init_ex(&hmac, context->SendSigningKey, 16, EVP_md5(), NULL); HMAC_Update(&hmac, (void*) &(MessageSeqNo), 4); HMAC_Update(&hmac, data, length); HMAC_Final(&hmac, digest, NULL); HMAC_CTX_cleanup(&hmac); /* Encrypt message using with RC4, result overwrites original buffer */ if (context->confidentiality) crypto_rc4(context->SendRc4Seal, length, data, data_buffer->pvBuffer); else memcpy(data_buffer->pvBuffer, data, length); xfree(data); #ifdef WITH_DEBUG_NTLM printf("Data Buffer (length = %d)\n", length); freerdp_hexdump(data, length); printf("\n"); printf("Encrypted Data Buffer (length = %d)\n", data_buffer->cbBuffer); freerdp_hexdump(data_buffer->pvBuffer, data_buffer->cbBuffer); printf("\n"); #endif /* RC4-encrypt first 8 bytes of digest */ crypto_rc4(context->SendRc4Seal, 8, digest, checksum); signature = (uint8*) signature_buffer->pvBuffer; /* Concatenate version, ciphertext and sequence number to build signature */ memcpy(signature, (void*) &version, 4); memcpy(&signature[4], (void*) checksum, 8); memcpy(&signature[12], (void*) &(MessageSeqNo), 4); context->SendSeqNum++; #ifdef WITH_DEBUG_NTLM printf("Signature (length = %d)\n", signature_buffer->cbBuffer); freerdp_hexdump(signature_buffer->pvBuffer, signature_buffer->cbBuffer); printf("\n"); #endif return SEC_E_OK; }