SECURITY_STATUS schannel_openssl_client_process_tokens(SCHANNEL_OPENSSL* context, PSecBufferDesc pInput, PSecBufferDesc pOutput) { int status; int ssl_error; PSecBuffer pBuffer; if (!context->connected) { if (pInput) { if (pInput->cBuffers < 1) return SEC_E_INVALID_TOKEN; pBuffer = sspi_FindSecBuffer(pInput, SECBUFFER_TOKEN); if (!pBuffer) return SEC_E_INVALID_TOKEN; status = BIO_write(context->bioRead, pBuffer->pvBuffer, pBuffer->cbBuffer); } status = SSL_connect(context->ssl); if (status < 0) { ssl_error = SSL_get_error(context->ssl, status); WLog_ERR(TAG, "SSL_connect error: %s", openssl_get_ssl_error_string(ssl_error)); } if (status == 1) context->connected = TRUE; status = BIO_read(context->bioWrite, context->ReadBuffer, SCHANNEL_CB_MAX_TOKEN); if (pOutput->cBuffers < 1) return SEC_E_INVALID_TOKEN; pBuffer = sspi_FindSecBuffer(pOutput, SECBUFFER_TOKEN); if (!pBuffer) return SEC_E_INVALID_TOKEN; if (status > 0) { if (pBuffer->cbBuffer < (unsigned long) status) return SEC_E_INSUFFICIENT_MEMORY; CopyMemory(pBuffer->pvBuffer, context->ReadBuffer, status); pBuffer->cbBuffer = status; return (context->connected) ? SEC_E_OK : SEC_I_CONTINUE_NEEDED; } else { pBuffer->cbBuffer = 0; return (context->connected) ? SEC_E_OK : SEC_I_CONTINUE_NEEDED; } } return SEC_E_OK; }
SECURITY_STATUS schannel_openssl_decrypt_message(SCHANNEL_OPENSSL* context, PSecBufferDesc pMessage) { int status; int length; BYTE* buffer; int ssl_error; PSecBuffer pBuffer; pBuffer = sspi_FindSecBuffer(pMessage, SECBUFFER_DATA); if (!pBuffer) return SEC_E_INVALID_TOKEN; status = BIO_write(context->bioRead, pBuffer->pvBuffer, pBuffer->cbBuffer); status = SSL_read(context->ssl, pBuffer->pvBuffer, pBuffer->cbBuffer); if (status < 0) { ssl_error = SSL_get_error(context->ssl, status); WLog_ERR(TAG, "SSL_read: %s", openssl_get_ssl_error_string(ssl_error)); } length = status; buffer = pBuffer->pvBuffer; pMessage->pBuffers[0].BufferType = SECBUFFER_STREAM_HEADER; pMessage->pBuffers[0].cbBuffer = 5; pMessage->pBuffers[1].BufferType = SECBUFFER_DATA; pMessage->pBuffers[1].pvBuffer = buffer; pMessage->pBuffers[1].cbBuffer = length; pMessage->pBuffers[2].BufferType = SECBUFFER_STREAM_TRAILER; pMessage->pBuffers[2].cbBuffer = 36; pMessage->pBuffers[3].BufferType = SECBUFFER_EMPTY; pMessage->pBuffers[3].cbBuffer = 0; return SEC_E_OK; }
SECURITY_STATUS schannel_openssl_encrypt_message(SCHANNEL_OPENSSL* context, PSecBufferDesc pMessage) { int status; int length; int offset; int ssl_error; PSecBuffer pStreamBodyBuffer; PSecBuffer pStreamHeaderBuffer; PSecBuffer pStreamTrailerBuffer; pStreamHeaderBuffer = sspi_FindSecBuffer(pMessage, SECBUFFER_STREAM_HEADER); pStreamBodyBuffer = sspi_FindSecBuffer(pMessage, SECBUFFER_DATA); pStreamTrailerBuffer = sspi_FindSecBuffer(pMessage, SECBUFFER_STREAM_TRAILER); if ((!pStreamHeaderBuffer) || (!pStreamBodyBuffer) || (!pStreamTrailerBuffer)) return SEC_E_INVALID_TOKEN; status = SSL_write(context->ssl, pStreamBodyBuffer->pvBuffer, pStreamBodyBuffer->cbBuffer); if (status < 0) { ssl_error = SSL_get_error(context->ssl, status); WLog_ERR(TAG, "SSL_write: %s", openssl_get_ssl_error_string(ssl_error)); } status = BIO_read(context->bioWrite, context->ReadBuffer, SCHANNEL_CB_MAX_TOKEN); if (status > 0) { offset = 0; length = (pStreamHeaderBuffer->cbBuffer > (unsigned long) status) ? status : pStreamHeaderBuffer->cbBuffer; CopyMemory(pStreamHeaderBuffer->pvBuffer, &context->ReadBuffer[offset], length); status -= length; offset += length; length = (pStreamBodyBuffer->cbBuffer > (unsigned long) status) ? status : pStreamBodyBuffer->cbBuffer; CopyMemory(pStreamBodyBuffer->pvBuffer, &context->ReadBuffer[offset], length); status -= length; offset += length; length = (pStreamTrailerBuffer->cbBuffer > (unsigned long) status) ? status : pStreamTrailerBuffer->cbBuffer; CopyMemory(pStreamTrailerBuffer->pvBuffer, &context->ReadBuffer[offset], length); } 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; }