BOOL ClientAuthenticate(const char *name, const char *hostname) { int rc, rcISC; SEC_WINNT_AUTH_IDENTITY nameAndPwd = {0}; int bytesReceived = 0, bytesSent = 0; char myTokenSource[256]; TimeStamp useBefore; DWORD ctxReq, ctxAttr; int dwRead,dwWritten; // input and output buffers SecBufferDesc obd, ibd; SecBuffer ob, ib[2]; BOOL haveInbuffer = FALSE; BOOL haveContext = FALSE; SCHANNEL_CRED cred = {0}; PCCERT_CONTEXT cert = NULL; HANDLE hMy = CertOpenSystemStore(0,"MY"); if(!hMy) { rcISC = SEC_E_NO_CREDENTIALS; server_error(1,"[%08x] %s\n",rcISC,GetErrorString(rcISC)); return FALSE; } if(name) { cert = CertFindCertificateInStore(hMy, X509_ASN_ENCODING, 0, CERT_FIND_SUBJECT_STR, (const wchar_t *)cvs::wide(name), NULL); if(!cert) { rcISC = SEC_E_NO_CREDENTIALS; server_error(1,"No certificate for '%s': %s\n",name,GetErrorString(rcISC)); return FALSE; } } cred.dwVersion = SCHANNEL_CRED_VERSION; cred.dwFlags = SCH_CRED_USE_DEFAULT_CREDS; if(cert) { cred.cCreds = 1; cred.paCred = &cert; } rc = AcquireCredentialsHandle( NULL, "SChannel", SECPKG_CRED_OUTBOUND, NULL, &cred, NULL, NULL, &credHandle, &useBefore ); ctxReq = ISC_REQ_MANUAL_CRED_VALIDATION | ISC_REQ_INTEGRITY | ISC_REQ_CONFIDENTIALITY | ISC_REQ_REPLAY_DETECT | ISC_REQ_SEQUENCE_DETECT | ISC_REQ_STREAM | ISC_REQ_USE_SUPPLIED_CREDS; strncpy(myTokenSource,hostname,sizeof(myTokenSource)); CertCloseStore(hMy,0); ib[0].pvBuffer = NULL; while ( 1 ) { obd.ulVersion = SECBUFFER_VERSION; obd.cBuffers = 1; obd.pBuffers = &ob; // just one buffer ob.BufferType = SECBUFFER_TOKEN; // preping a token here ob.cbBuffer = secPackInfo->cbMaxToken; ob.pvBuffer = malloc(secPackInfo->cbMaxToken); rcISC = InitializeSecurityContext( &credHandle, haveContext? &contextHandle: NULL, myTokenSource, ctxReq, 0, SECURITY_NATIVE_DREP, haveInbuffer? &ibd: NULL, 0, &contextHandle, &obd, &ctxAttr, &useBefore ); if ( ib[0].pvBuffer != NULL ) { free(ib[0].pvBuffer); ib[0].pvBuffer = NULL; } if ( rcISC == SEC_I_COMPLETE_AND_CONTINUE || rcISC == SEC_I_COMPLETE_NEEDED ) { CompleteAuthToken( &contextHandle, &obd ); if ( rcISC == SEC_I_COMPLETE_NEEDED ) rcISC = SEC_E_OK; else if ( rcISC == SEC_I_COMPLETE_AND_CONTINUE ) rcISC = SEC_I_CONTINUE_NEEDED; } if(rcISC<0) { server_error(1,"[%08x] %s\n",rcISC,GetErrorString(rcISC)); } // send the output buffer off to the server if ( ob.cbBuffer != 0 ) { if((dwWritten=tcp_write( (const char *) ob.pvBuffer, ob.cbBuffer))<=0) break; bytesSent += dwWritten; } free(ob.pvBuffer); ob.pvBuffer = NULL; ob.cbBuffer = 0; if ( rcISC != SEC_I_CONTINUE_NEEDED ) break; // prepare to get the server's response ibd.ulVersion = SECBUFFER_VERSION; ibd.cBuffers = 2; ibd.pBuffers = ib; // just one buffer ib[0].BufferType = SECBUFFER_TOKEN; // preping a token here ib[0].cbBuffer = secPackInfo->cbMaxToken; ib[0].pvBuffer = malloc(secPackInfo->cbMaxToken); ib[1].cbBuffer = 0; ib[1].pvBuffer = NULL; ib[1].BufferType = SECBUFFER_EMPTY; // Spare stuff // receive the server's response if((dwRead=tcp_read(ib[0].pvBuffer,ib[0].cbBuffer))<=0) break; bytesReceived += dwRead; // by now we have an input buffer and a client context haveInbuffer = TRUE; haveContext = TRUE; } // we arrive here as soon as InitializeSecurityContext() // returns != SEC_I_CONTINUE_NEEDED. if ( rcISC != SEC_E_OK ) haveContext = FALSE; else haveContext = TRUE; /* Looopback kerberos needs this */ return haveContext; }
void test() { SchannelCredential schannelCredential(SECPKG_CRED_OUTBOUND, NULL); CtxtHandle contextHandle; SecBufferArray<1> outputBufferArray; initializeSecBuffer(outputBufferArray[0], SECBUFFER_TOKEN, tokenBuffer, sizeof(tokenBuffer)); ULONG contextAttributes; SECURITY_STATUS result = InitializeSecurityContext( &schannelCredential.getHandle(), NULL, NULL, 0, 0, 0, NULL, 0, &contextHandle, &outputBufferArray.getDescriptor(), &contextAttributes, NULL); std::cout << outputBufferArray[0].cbBuffer << '\n'; }
void LSSLContext::Shutdown(LSockByteStream* SockByteStream, const TCHAR* TargetName) { //SSPI: отключение от сервера //сначала выставим нужный статус у контекста DWORD ShutdownToken = SCHANNEL_SHUTDOWN; SecBufferDesc ShutDownBufferDesc; SecBuffer ShutDownBuffers[1]; ShutDownBufferDesc.cBuffers = 1; ShutDownBufferDesc.pBuffers = ShutDownBuffers; ShutDownBufferDesc.ulVersion = SECBUFFER_VERSION; ShutDownBuffers[0].pvBuffer = &ShutdownToken; ShutDownBuffers[0].BufferType = SECBUFFER_TOKEN; ShutDownBuffers[0].cbBuffer = sizeof(ShutdownToken); //VERIFY(SEC_E_OK==ApplyControlToken(GetContextHandle(), &ShutDownBufferDesc)); //затем получим данные для отправки ShutDownBuffers[0].BufferType = SECBUFFER_TOKEN; ShutDownBuffers[0].pvBuffer = 0; ShutDownBuffers[0].cbBuffer = 0; /*VERIFY(SEC_E_OK==*/InitializeSecurityContext(&m_hUserCred, GetContextHandle(), const_cast<TCHAR*>(TargetName), m_ReqContextAttr, 0, 0, 0, 0, 0, &ShutDownBufferDesc, &m_ContextAttr, &m_ContextExpiry)/*)*/; //ASSERT(ShutDownBuffers[0].pvBuffer&&ShutDownBuffers[0].cbBuffer); //WS: отправим обработанные SCHANNEL данные SockByteStream->RawSend(ShutDownBuffers[0].pvBuffer, ShutDownBuffers[0].cbBuffer); FreeContextBuffer(ShutDownBuffers[0].pvBuffer); ShutDownBuffers[0].pvBuffer=0; ShutDownBuffers[0].cbBuffer=0; }
/* sqAuthContinue: Submit a token to the authentication session. Arguments: handle - the authentication session handle token - the pointer to the token data tokensize - the length of the token data. Returns: An integer status code. <0 - Error. The error code is platform specific. 0 - OK. The session is authenticated. 1 - Another server-roundtrip is needed. */ int sqAuthContinue(int handle, char *token, int tokensize) { sqAuthData *auth = (sqAuthData*)handle; SECURITY_STATUS ret; ULONG flags = DEFAULT_AUTH_FLAGS; ULONG attrs = 0; if(auth == NULL) return -1; auth->inbuf[0].BufferType = SECBUFFER_TOKEN; auth->inbuf[0].cbBuffer = tokensize; auth->inbuf[0].pvBuffer = token; auth->inbuf[1].BufferType = SECBUFFER_EMPTY; auth->inbuf[1].cbBuffer = 0; auth->inbuf[1].pvBuffer = NULL; auth->sbdIn.cBuffers = 2; ret = InitializeSecurityContext(&auth->cred, &auth->ctxt, auth->principal, flags, 0, SECURITY_NETWORK_DREP, &auth->sbdIn, 0, NULL, &auth->sbdOut, &attrs, NULL); if (FAILED(ret)) { if(debug) printf("InitializeSecurityContext failed: %x\n", ret); return -(ret & 0x7FFFFFFF); } if(debug) printf("InitializeSecurityContext returned: %x\n", ret); /* Complete token if needed */ if(ret == SEC_I_COMPLETE_NEEDED || ret == SEC_I_COMPLETE_AND_CONTINUE) { SECURITY_STATUS ss; ss = CompleteAuthToken (&auth->ctxt, &auth->sbdOut); if(FAILED(ss)) { if(debug) printf("CompleteAuthToken failed: %x\n", ss); return ss; } } if(ret == SEC_E_OK || ret == SEC_I_COMPLETE_NEEDED) { /* success; session is established */ return 0; } if(ret == SEC_I_CONTINUE_NEEDED || ret == SEC_I_COMPLETE_AND_CONTINUE) { /* need another round trip */ return 1; } return -ret; }
int SSL_SOCKET :: ClientOff() { // Client wants to disconnect SECURITY_STATUS ss; Z<SecBuffer> OutBuffers(100); DWORD dwType = SCHANNEL_SHUTDOWN; OutBuffers[0].pvBuffer = &dwType; OutBuffers[0].BufferType = SECBUFFER_TOKEN; OutBuffers[0].cbBuffer = sizeof(dwType); sbout.cBuffers = 1; sbout.pBuffers = OutBuffers; sbout.ulVersion = SECBUFFER_VERSION; for(;;) { ss = ApplyControlToken(&hCtx, &sbout); if (FAILED(ss)) return -1; DWORD dwSSPIFlags; DWORD dwSSPIOutFlags; dwSSPIFlags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT | ISC_REQ_CONFIDENTIALITY | ISC_RET_EXTENDED_ERROR | ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM; OutBuffers[0].pvBuffer = NULL; OutBuffers[0].BufferType = SECBUFFER_TOKEN; OutBuffers[0].cbBuffer = 0; sbout.cBuffers = 1; sbout.pBuffers = OutBuffers; sbout.ulVersion = SECBUFFER_VERSION; ss = InitializeSecurityContext(&hCred,&hCtx,NULL,dwSSPIFlags,0,SECURITY_NATIVE_DREP, NULL,0,&hCtx,&sbout,&dwSSPIOutFlags,0); if (FAILED(ss)) return -1; PBYTE pbMessage; DWORD cbMessage; pbMessage = (BYTE *)(OutBuffers[0].pvBuffer); cbMessage = OutBuffers[0].cbBuffer; if (pbMessage != NULL && cbMessage != 0) { int rval = ssend_p((char*)pbMessage, cbMessage); FreeContextBuffer(pbMessage); return rval; } break; } return 1; }
static int tls_client_handshake(URLContext *h) { TLSContext *c = h->priv_data; TLSShared *s = &c->tls_shared; SecBuffer outbuf; SecBufferDesc outbuf_desc; SECURITY_STATUS sspi_ret; int ret; init_sec_buffer(&outbuf, SECBUFFER_EMPTY, NULL, 0); init_sec_buffer_desc(&outbuf_desc, &outbuf, 1); c->request_flags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT | ISC_REQ_CONFIDENTIALITY | ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM; sspi_ret = InitializeSecurityContext(&c->cred_handle, NULL, s->host, c->request_flags, 0, 0, NULL, 0, &c->ctxt_handle, &outbuf_desc, &c->context_flags, &c->ctxt_timestamp); if (sspi_ret != SEC_I_CONTINUE_NEEDED) { av_log(h, AV_LOG_ERROR, "Unable to create initial security context (0x%lx)\n", sspi_ret); ret = AVERROR_UNKNOWN; goto fail; } ret = ffurl_write(s->tcp, outbuf.pvBuffer, outbuf.cbBuffer); FreeContextBuffer(outbuf.pvBuffer); if (ret < 0 || ret != outbuf.cbBuffer) { av_log(h, AV_LOG_ERROR, "Failed to send initial handshake data\n"); ret = AVERROR(EIO); goto fail; } return tls_client_handshake_loop(h, 1); fail: DeleteSecurityContext(&c->ctxt_handle); return ret; }
static int tls_shutdown_client(URLContext *h) { TLSContext *c = h->priv_data; TLSShared *s = &c->tls_shared; int ret; if (c->connected) { SecBufferDesc BuffDesc; SecBuffer Buffer; SECURITY_STATUS sspi_ret; SecBuffer outbuf; SecBufferDesc outbuf_desc; DWORD dwshut = SCHANNEL_SHUTDOWN; init_sec_buffer(&Buffer, SECBUFFER_TOKEN, &dwshut, sizeof(dwshut)); init_sec_buffer_desc(&BuffDesc, &Buffer, 1); sspi_ret = ApplyControlToken(&c->ctxt_handle, &BuffDesc); if (sspi_ret != SEC_E_OK) av_log(h, AV_LOG_ERROR, "ApplyControlToken failed\n"); init_sec_buffer(&outbuf, SECBUFFER_EMPTY, NULL, 0); init_sec_buffer_desc(&outbuf_desc, &outbuf, 1); sspi_ret = InitializeSecurityContext(&c->cred_handle, &c->ctxt_handle, s->host, c->request_flags, 0, 0, NULL, 0, &c->ctxt_handle, &outbuf_desc, &c->context_flags, &c->ctxt_timestamp); if (sspi_ret == SEC_E_OK || sspi_ret == SEC_I_CONTEXT_EXPIRED) { ret = ffurl_write(s->tcp, outbuf.pvBuffer, outbuf.cbBuffer); FreeContextBuffer(outbuf.pvBuffer); if (ret < 0 || ret != outbuf.cbBuffer) av_log(h, AV_LOG_ERROR, "Failed to send close message\n"); } c->connected = 0; } return 0; }
static DWORD ClientEstablishContext( IN PCSTR pSPN, IN INT nSocket, IN PCSTR pServiceName, IN PCSTR pServicePassword, IN PCSTR pServiceRealm, IN ULONG DelegFlag, OUT CtxtHandle *pSspiContext, IN PCSTR pSecPkgName, OUT ULONG *pRetFlags ) { DWORD dwError = ERROR_SUCCESS; DWORD dwLoopError = ERROR_SUCCESS; PCtxtHandle pContextHandle = NULL; INT nCredentialsAcquired = 0; INT nContextAcquired = 0; SecBuffer SendTokenBuffer; SecBuffer RecvTokenBuffer; SecBufferDesc InputDesc; SecBufferDesc OutputDesc; CredHandle CredHandle; TimeStamp Expiry; SEC_WINNT_AUTH_IDENTITY AuthIdentity; PSEC_WINNT_AUTH_IDENTITY pAuthId = NULL; memset(&SendTokenBuffer, 0, sizeof(SecBuffer)); memset(&RecvTokenBuffer, 0, sizeof(SecBuffer)); memset(&InputDesc, 0, sizeof(SecBufferDesc)); memset(&OutputDesc, 0, sizeof(SecBufferDesc)); memset(&CredHandle, 0, sizeof(CredHandle)); memset(&Expiry, 0, sizeof(TimeStamp)); memset(&AuthIdentity, 0, sizeof(AuthIdentity)); memset(pSspiContext, 0, sizeof(CtxtHandle)); *pRetFlags = 0; InputDesc.cBuffers = 1; InputDesc.pBuffers = &RecvTokenBuffer; InputDesc.ulVersion = SECBUFFER_VERSION; RecvTokenBuffer.BufferType = SECBUFFER_TOKEN; RecvTokenBuffer.cbBuffer = 0; RecvTokenBuffer.pvBuffer = NULL; OutputDesc.cBuffers = 1; OutputDesc.pBuffers = &SendTokenBuffer; OutputDesc.ulVersion = SECBUFFER_VERSION; SendTokenBuffer.BufferType = SECBUFFER_TOKEN; SendTokenBuffer.cbBuffer = 0; SendTokenBuffer.pvBuffer = NULL; CredHandle.dwLower = 0; CredHandle.dwUpper = 0; if (pServiceName) { AuthIdentity.User = (PBYTE) pServiceName; AuthIdentity.UserLength = (DWORD)strlen(pServiceName); pAuthId = &AuthIdentity; } if (pServicePassword) { AuthIdentity.Password = (PBYTE) pServicePassword; AuthIdentity.PasswordLength = (DWORD)strlen(pServicePassword); pAuthId = &AuthIdentity; } if (pServiceRealm) { AuthIdentity.Domain = (PBYTE) pServiceRealm; AuthIdentity.DomainLength = (DWORD)strlen(pServiceRealm); pAuthId = &AuthIdentity; } AuthIdentity.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI; dwError = AcquireCredentialsHandle( NULL, // no principal name (PSTR) pSecPkgName, // package name SECPKG_CRED_OUTBOUND, NULL, // no logon id pAuthId, NULL, // no get key fn NULL, // noget key arg &CredHandle, &Expiry ); BAIL_ON_ERROR(dwError); nCredentialsAcquired = 1; /* * Perform the context-establishement loop. */ pSspiContext->dwLower = 0; pSspiContext->dwUpper = 0; do { // we need to use dwLoopErr in this case because we may get // back a "continue" command. In those cases, we still // need dwError to be used and set seperatly based on other // calls. dwLoopError = InitializeSecurityContext( &CredHandle, pContextHandle, (PSTR) pSPN, DelegFlag, 0, // reserved SECURITY_NATIVE_DREP, &InputDesc, 0, // reserved pSspiContext, &OutputDesc, pRetFlags, &Expiry ); if (SEC_E_OK != dwLoopError && SEC_I_CONTINUE_NEEDED != dwLoopError) { dwError = dwLoopError; BAIL_ON_ERROR(dwError); } nContextAcquired = 1; if (SEC_I_CONTINUE_NEEDED == dwLoopError) { PNTLM_NEGOTIATE_MESSAGE pMsg = (PNTLM_NEGOTIATE_MESSAGE) SendTokenBuffer.pvBuffer; // Adjust any flags for debugging // pMsg->NtlmFlags |= NTLM_FLAG_SEAL; printf("Context partially initialized...\n"); DumpBuffer(SendTokenBuffer.pvBuffer, SendTokenBuffer.cbBuffer); DumpNtlmMessage(SendTokenBuffer.pvBuffer, SendTokenBuffer.cbBuffer); printf("\n"); printf("Flags returned:\n"); DumpIscRetFlags(*pRetFlags); printf("\n"); } else { PNTLM_RESPONSE_MESSAGE pMsg = (PNTLM_RESPONSE_MESSAGE) SendTokenBuffer.pvBuffer; // Adjust any flags for debugging //pMsg->NtlmFlags |= NTLM_FLAG_SEAL; printf("Context FULLY initialized!\n"); DumpBuffer(SendTokenBuffer.pvBuffer, SendTokenBuffer.cbBuffer); DumpNtlmMessage(SendTokenBuffer.pvBuffer, SendTokenBuffer.cbBuffer); printf("\n"); printf("Flags returned:\n"); DumpIscRetFlags(*pRetFlags); printf("\n"); } pContextHandle = pSspiContext; if (RecvTokenBuffer.pvBuffer) { free(RecvTokenBuffer.pvBuffer); RecvTokenBuffer.pvBuffer = NULL; RecvTokenBuffer.cbBuffer = 0; } if (SendTokenBuffer.cbBuffer != 0) { dwError = SendToken(nSocket, &SendTokenBuffer); BAIL_ON_ERROR(dwError); } FreeContextBuffer(SendTokenBuffer.pvBuffer); SendTokenBuffer.pvBuffer = NULL; SendTokenBuffer.cbBuffer = 0; if (SEC_I_CONTINUE_NEEDED == dwLoopError) { dwError = RecvToken(nSocket, &RecvTokenBuffer); BAIL_ON_ERROR(dwError); printf("RECEIVED:\n"); DumpBuffer(RecvTokenBuffer.pvBuffer, RecvTokenBuffer.cbBuffer); DumpNtlmMessage(RecvTokenBuffer.pvBuffer, RecvTokenBuffer.cbBuffer); printf("\n"); } } while (dwLoopError == SEC_I_CONTINUE_NEEDED); FreeCredentialsHandle(&CredHandle); finish: return dwError; error: if (nCredentialsAcquired) { FreeCredentialsHandle(&CredHandle); } if (nContextAcquired) { DeleteSecurityContext(pSspiContext); memset(pSspiContext, 0, sizeof(CtxtHandle)); } if (RecvTokenBuffer.pvBuffer) { free(RecvTokenBuffer.pvBuffer); } if (SendTokenBuffer.cbBuffer) { FreeContextBuffer(SendTokenBuffer.pvBuffer); } goto finish; }
/* * '_sspiConnect()' - Make an SSL connection. This function * assumes a TCP/IP connection has already * been successfully made */ BOOL /* O - 1 on success, 0 on failure */ _sspiConnect(_sspi_struct_t *conn, /* I - Client connection */ const CHAR *hostname) /* I - Server hostname */ { PCCERT_CONTEXT serverCert; /* Server certificate */ DWORD dwSSPIFlags; /* SSL connection attributes we want */ DWORD dwSSPIOutFlags; /* SSL connection attributes we got */ TimeStamp tsExpiry; /* Time stamp */ SECURITY_STATUS scRet; /* Status */ DWORD cbData; /* Data count */ SecBufferDesc inBuffer; /* Array of SecBuffer structs */ SecBuffer inBuffers[2]; /* Security package buffer */ SecBufferDesc outBuffer; /* Array of SecBuffer structs */ SecBuffer outBuffers[1]; /* Security package buffer */ BOOL ok = TRUE; /* Return value */ serverCert = NULL; dwSSPIFlags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT | ISC_REQ_CONFIDENTIALITY | ISC_RET_EXTENDED_ERROR | ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM; /* * Initiate a ClientHello message and generate a token. */ outBuffers[0].pvBuffer = NULL; outBuffers[0].BufferType = SECBUFFER_TOKEN; outBuffers[0].cbBuffer = 0; outBuffer.cBuffers = 1; outBuffer.pBuffers = outBuffers; outBuffer.ulVersion = SECBUFFER_VERSION; scRet = InitializeSecurityContext(&conn->creds, NULL, TEXT(""), dwSSPIFlags, 0, SECURITY_NATIVE_DREP, NULL, 0, &conn->context, &outBuffer, &dwSSPIOutFlags, &tsExpiry); if (scRet != SEC_I_CONTINUE_NEEDED) { DEBUG_printf(("_sspiConnect: InitializeSecurityContext(1) failed: %x", scRet)); ok = FALSE; goto cleanup; } /* * Send response to server if there is one. */ if (outBuffers[0].cbBuffer && outBuffers[0].pvBuffer) { cbData = send(conn->sock, outBuffers[0].pvBuffer, outBuffers[0].cbBuffer, 0); if ((cbData == SOCKET_ERROR) || !cbData) { DEBUG_printf(("_sspiConnect: send failed: %d", WSAGetLastError())); FreeContextBuffer(outBuffers[0].pvBuffer); DeleteSecurityContext(&conn->context); ok = FALSE; goto cleanup; } DEBUG_printf(("_sspiConnect: %d bytes of handshake data sent", cbData)); /* * Free output buffer. */ FreeContextBuffer(outBuffers[0].pvBuffer); outBuffers[0].pvBuffer = NULL; } dwSSPIFlags = ISC_REQ_MANUAL_CRED_VALIDATION | ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT | ISC_REQ_CONFIDENTIALITY | ISC_RET_EXTENDED_ERROR | ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM; conn->decryptBufferUsed = 0; /* * Loop until the handshake is finished or an error occurs. */ scRet = SEC_I_CONTINUE_NEEDED; while(scRet == SEC_I_CONTINUE_NEEDED || scRet == SEC_E_INCOMPLETE_MESSAGE || scRet == SEC_I_INCOMPLETE_CREDENTIALS) { if ((conn->decryptBufferUsed == 0) || (scRet == SEC_E_INCOMPLETE_MESSAGE)) { if (conn->decryptBufferLength <= conn->decryptBufferUsed) { conn->decryptBufferLength += 4096; conn->decryptBuffer = (BYTE*) realloc(conn->decryptBuffer, conn->decryptBufferLength); if (!conn->decryptBuffer) { DEBUG_printf(("_sspiConnect: unable to allocate %d byte decrypt buffer", conn->decryptBufferLength)); SetLastError(E_OUTOFMEMORY); ok = FALSE; goto cleanup; } } cbData = recv(conn->sock, conn->decryptBuffer + conn->decryptBufferUsed, (int) (conn->decryptBufferLength - conn->decryptBufferUsed), 0); if (cbData == SOCKET_ERROR) { DEBUG_printf(("_sspiConnect: recv failed: %d", WSAGetLastError())); ok = FALSE; goto cleanup; } else if (cbData == 0) { DEBUG_printf(("_sspiConnect: server unexpectedly disconnected")); ok = FALSE; goto cleanup; } DEBUG_printf(("_sspiConnect: %d bytes of handshake data received", cbData)); conn->decryptBufferUsed += cbData; } /* * Set up the input buffers. Buffer 0 is used to pass in data * received from the server. Schannel will consume some or all * of this. Leftover data (if any) will be placed in buffer 1 and * given a buffer type of SECBUFFER_EXTRA. */ inBuffers[0].pvBuffer = conn->decryptBuffer; inBuffers[0].cbBuffer = (unsigned long) conn->decryptBufferUsed; inBuffers[0].BufferType = SECBUFFER_TOKEN; inBuffers[1].pvBuffer = NULL; inBuffers[1].cbBuffer = 0; inBuffers[1].BufferType = SECBUFFER_EMPTY; inBuffer.cBuffers = 2; inBuffer.pBuffers = inBuffers; inBuffer.ulVersion = SECBUFFER_VERSION; /* * Set up the output buffers. These are initialized to NULL * so as to make it less likely we'll attempt to free random * garbage later. */ outBuffers[0].pvBuffer = NULL; outBuffers[0].BufferType= SECBUFFER_TOKEN; outBuffers[0].cbBuffer = 0; outBuffer.cBuffers = 1; outBuffer.pBuffers = outBuffers; outBuffer.ulVersion = SECBUFFER_VERSION; /* * Call InitializeSecurityContext. */ scRet = InitializeSecurityContext(&conn->creds, &conn->context, NULL, dwSSPIFlags, 0, SECURITY_NATIVE_DREP, &inBuffer, 0, NULL, &outBuffer, &dwSSPIOutFlags, &tsExpiry); /* * If InitializeSecurityContext was successful (or if the error was * one of the special extended ones), send the contends of the output * buffer to the server. */ if (scRet == SEC_E_OK || scRet == SEC_I_CONTINUE_NEEDED || FAILED(scRet) && (dwSSPIOutFlags & ISC_RET_EXTENDED_ERROR)) { if (outBuffers[0].cbBuffer && outBuffers[0].pvBuffer) { cbData = send(conn->sock, outBuffers[0].pvBuffer, outBuffers[0].cbBuffer, 0); if ((cbData == SOCKET_ERROR) || !cbData) { DEBUG_printf(("_sspiConnect: send failed: %d", WSAGetLastError())); FreeContextBuffer(outBuffers[0].pvBuffer); DeleteSecurityContext(&conn->context); ok = FALSE; goto cleanup; } DEBUG_printf(("_sspiConnect: %d bytes of handshake data sent", cbData)); /* * Free output buffer. */ FreeContextBuffer(outBuffers[0].pvBuffer); outBuffers[0].pvBuffer = NULL; } } /* * If InitializeSecurityContext returned SEC_E_INCOMPLETE_MESSAGE, * then we need to read more data from the server and try again. */ if (scRet == SEC_E_INCOMPLETE_MESSAGE) continue; /* * If InitializeSecurityContext returned SEC_E_OK, then the * handshake completed successfully. */ if (scRet == SEC_E_OK) { /* * If the "extra" buffer contains data, this is encrypted application * protocol layer stuff. It needs to be saved. The application layer * will later decrypt it with DecryptMessage. */ DEBUG_printf(("_sspiConnect: Handshake was successful")); if (inBuffers[1].BufferType == SECBUFFER_EXTRA) { if (conn->decryptBufferLength < inBuffers[1].cbBuffer) { conn->decryptBuffer = realloc(conn->decryptBuffer, inBuffers[1].cbBuffer); if (!conn->decryptBuffer) { DEBUG_printf(("_sspiConnect: unable to allocate %d bytes for decrypt buffer", inBuffers[1].cbBuffer)); SetLastError(E_OUTOFMEMORY); ok = FALSE; goto cleanup; } } memmove(conn->decryptBuffer, conn->decryptBuffer + (conn->decryptBufferUsed - inBuffers[1].cbBuffer), inBuffers[1].cbBuffer); conn->decryptBufferUsed = inBuffers[1].cbBuffer; DEBUG_printf(("_sspiConnect: %d bytes of app data was bundled with handshake data", conn->decryptBufferUsed)); } else conn->decryptBufferUsed = 0; /* * Bail out to quit */ break; } /* * Check for fatal error. */ if (FAILED(scRet)) { DEBUG_printf(("_sspiConnect: InitializeSecurityContext(2) failed: %x", scRet)); ok = FALSE; break; } /* * If InitializeSecurityContext returned SEC_I_INCOMPLETE_CREDENTIALS, * then the server just requested client authentication. */ if (scRet == SEC_I_INCOMPLETE_CREDENTIALS) { /* * Unimplemented */ DEBUG_printf(("_sspiConnect: server requested client credentials")); ok = FALSE; break; } /* * Copy any leftover data from the "extra" buffer, and go around * again. */ if (inBuffers[1].BufferType == SECBUFFER_EXTRA) { memmove(conn->decryptBuffer, conn->decryptBuffer + (conn->decryptBufferUsed - inBuffers[1].cbBuffer), inBuffers[1].cbBuffer); conn->decryptBufferUsed = inBuffers[1].cbBuffer; } else { conn->decryptBufferUsed = 0; } } if (ok) { conn->contextInitialized = TRUE; /* * Get the server cert */ scRet = QueryContextAttributes(&conn->context, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (VOID*) &serverCert ); if (scRet != SEC_E_OK) { DEBUG_printf(("_sspiConnect: QueryContextAttributes failed(SECPKG_ATTR_REMOTE_CERT_CONTEXT): %x", scRet)); ok = FALSE; goto cleanup; } scRet = sspi_verify_certificate(serverCert, hostname, conn->certFlags); if (scRet != SEC_E_OK) { DEBUG_printf(("_sspiConnect: sspi_verify_certificate failed: %x", scRet)); ok = FALSE; goto cleanup; } /* * Find out how big the header/trailer will be: */ scRet = QueryContextAttributes(&conn->context, SECPKG_ATTR_STREAM_SIZES, &conn->streamSizes); if (scRet != SEC_E_OK) { DEBUG_printf(("_sspiConnect: QueryContextAttributes failed(SECPKG_ATTR_STREAM_SIZES): %x", scRet)); ok = FALSE; } } cleanup: if (serverCert) CertFreeCertificateContext(serverCert); return (ok); }
BOOL GenClientContext ( BYTE *pIn, DWORD cbIn, BYTE *pOut, DWORD *pcbOut, BOOL *pfDone, CHAR *pszTarget, CredHandle *hCred, struct _SecHandle *hcText) { SECURITY_STATUS ss; TimeStamp Lifetime; SecBufferDesc OutBuffDesc; SecBuffer OutSecBuff; SecBufferDesc InBuffDesc; SecBuffer InSecBuff; ULONG ContextAttributes; static TCHAR lpPackageName[1024]; if( NULL == pIn ) { strcpy_s(lpPackageName, 1024 * sizeof(TCHAR), "Negotiate"); ss = AcquireCredentialsHandle ( NULL, lpPackageName, SECPKG_CRED_OUTBOUND, NULL, NULL, NULL, NULL, hCred, &Lifetime); if (!(SEC_SUCCESS (ss))) { MyHandleError("AcquireCreds failed "); } } //-------------------------------------------------------------------- // Prepare the buffers. OutBuffDesc.ulVersion = 0; OutBuffDesc.cBuffers = 1; OutBuffDesc.pBuffers = &OutSecBuff; OutSecBuff.cbBuffer = *pcbOut; OutSecBuff.BufferType = SECBUFFER_TOKEN; OutSecBuff.pvBuffer = pOut; //------------------------------------------------------------------- // The input buffer is created only if a message has been received // from the server. if (pIn) { InBuffDesc.ulVersion = 0; InBuffDesc.cBuffers = 1; InBuffDesc.pBuffers = &InSecBuff; InSecBuff.cbBuffer = cbIn; InSecBuff.BufferType = SECBUFFER_TOKEN; InSecBuff.pvBuffer = pIn; ss = InitializeSecurityContext ( hCred, hcText, pszTarget, MessageAttribute, 0, SECURITY_NATIVE_DREP, &InBuffDesc, 0, hcText, &OutBuffDesc, &ContextAttributes, &Lifetime); } else { ss = InitializeSecurityContext ( hCred, NULL, pszTarget, MessageAttribute, 0, SECURITY_NATIVE_DREP, NULL, 0, hcText, &OutBuffDesc, &ContextAttributes, &Lifetime); } if (!SEC_SUCCESS (ss)) { MyHandleError ("InitializeSecurityContext failed " ); } //------------------------------------------------------------------- // If necessary, complete the token. if ((SEC_I_COMPLETE_NEEDED == ss) || (SEC_I_COMPLETE_AND_CONTINUE == ss)) { ss = CompleteAuthToken (hcText, &OutBuffDesc); if (!SEC_SUCCESS(ss)) { fprintf (stderr, "complete failed: 0x%08x\n", ss); return FALSE; } } *pcbOut = OutSecBuff.cbBuffer; *pfDone = !((SEC_I_CONTINUE_NEEDED == ss) || (SEC_I_COMPLETE_AND_CONTINUE == ss)); printf ("Token buffer generated (%lu bytes):\n", OutSecBuff.cbBuffer); PrintHexDump (OutSecBuff.cbBuffer, (PBYTE)OutSecBuff.pvBuffer); return TRUE; }
int SSL_SOCKET :: ClientLoop() { SECURITY_STATUS ss = SEC_I_CONTINUE_NEEDED; Z<char> t(0x11000); Z<SecBuffer> bufsi(100); Z<SecBuffer> bufso(100); int pt = 0; // Loop using InitializeSecurityContext until success for(;;) { if (ss != SEC_I_CONTINUE_NEEDED && ss != SEC_E_INCOMPLETE_MESSAGE && ss != SEC_I_INCOMPLETE_CREDENTIALS) break; DWORD dwSSPIFlags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT | ISC_REQ_CONFIDENTIALITY | ISC_RET_EXTENDED_ERROR | ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM; dwSSPIFlags |= ISC_REQ_MANUAL_CRED_VALIDATION; if (InitContext == 0) { // Initialize sbout bufso[0].pvBuffer = NULL; bufso[0].BufferType = SECBUFFER_TOKEN; bufso[0].cbBuffer = 0; sbout.ulVersion = SECBUFFER_VERSION; sbout.cBuffers = 1; sbout.pBuffers = bufso; } else { // Get Some data from the remote site // Add also extradata? if (ExtraDataSize) { memcpy(t,ExtraData,ExtraDataSize); pt += ExtraDataSize; ExtraDataSize = 0; } int rval = recv(X,t + pt,0x10000,0); if (rval == 0 || rval == -1) return rval; pt += rval; // Put this data into the buffer so InitializeSecurityContext will do bufsi[0].BufferType = SECBUFFER_TOKEN; bufsi[0].cbBuffer = pt; bufsi[0].pvBuffer = t; bufsi[1].BufferType = SECBUFFER_EMPTY; bufsi[1].cbBuffer = 0; bufsi[1].pvBuffer = 0; sbin.ulVersion = SECBUFFER_VERSION; sbin.pBuffers = bufsi; sbin.cBuffers = 2; bufso[0].pvBuffer = NULL; bufso[0].BufferType= SECBUFFER_TOKEN; bufso[0].cbBuffer = 0; sbout.cBuffers = 1; sbout.pBuffers = bufso; sbout.ulVersion = SECBUFFER_VERSION; } DWORD dwSSPIOutFlags = 0; SEC_E_INTERNAL_ERROR; ss = InitializeSecurityContext( &hCred, InitContext ? &hCtx : 0, dn, dwSSPIFlags, 0, 0,//SECURITY_NATIVE_DREP, InitContext ? &sbin : 0, 0, InitContext ? 0 : &hCtx, &sbout, &dwSSPIOutFlags, 0); if (ss == SEC_E_INCOMPLETE_MESSAGE) continue; // allow more pt = 0; if (FAILED(ss)) return -1; if (InitContext == 0 && ss != SEC_I_CONTINUE_NEEDED) return -1; // Handle possible ExtraData /* if (bufsi[1].BufferType == SECBUFFER_EXTRA) { ExtraDataSize = bufsi[1].cbBuffer; ExtraData.Resize(ExtraDataSize + 10); memcpy(ExtraData,bufsi[1].pvBuffer,ExtraDataSize); } */ if (!InitContext) { // Send the data we got to the remote part //cbData = Send(OutBuffers[0].pvBuffer,OutBuffers[0].cbBuffer); int rval = ssend_p((char*)bufso[0].pvBuffer,bufso[0].cbBuffer); FreeContextBuffer(bufso[0].pvBuffer); if (rval != bufso[0].cbBuffer) return -1; InitContext = true; continue; } // Pass data to the remote site int rval = ssend_p((char*)bufso[0].pvBuffer,bufso[0].cbBuffer); FreeContextBuffer(bufso[0].pvBuffer); if (rval != bufso[0].cbBuffer) return -1; if (ss == S_OK) break; // wow!! } return 0; }
void LSSLContext::Handshake(LSockByteStream* SockByteStream, const TCHAR* TargetName) { SecPkgInfo* PkgInfo; /*VERIFY(SEC_E_OK==*/QuerySecurityPackageInfo(UNISP_NAME, &PkgInfo)/*)*/; std::vector<BYTE> SockDataBuf(PkgInfo->cbMaxToken); FreeContextBuffer(PkgInfo); //SSPI:HandShake SecBufferDesc InBufferDesc; SecBuffer InBuffers[2]; InBufferDesc.ulVersion = SECBUFFER_VERSION; InBufferDesc.pBuffers = InBuffers; InBufferDesc.cBuffers = 2; SecBufferDesc OutBufferDesc; SecBuffer OutBuffers[1]; OutBufferDesc.ulVersion = SECBUFFER_VERSION; OutBufferDesc.pBuffers = OutBuffers; OutBufferDesc.cBuffers = 1; //первичное обращение об инициализации контекста OutBuffers[0].BufferType = SECBUFFER_TOKEN; OutBuffers[0].pvBuffer = NULL; OutBuffers[0].cbBuffer = 0; SECURITY_STATUS sec_s = InitializeSecurityContext(&m_hUserCred, 0, const_cast<TCHAR*>(TargetName), m_ReqContextAttr, 0, 0, NULL, 0, &m_hContext, &OutBufferDesc, &m_ContextAttr, &m_ContextExpiry); //ASSERT(SEC_E_OK==sec_s||SEC_I_CONTINUE_NEEDED==sec_s); unsigned int SockDataSize=0; bool WasExtra=false; while(SEC_I_CONTINUE_NEEDED==sec_s){ //оба поля должны быть либо указаны либо не указаны, т.к. иначе не совсем понятно что это означает //ASSERT((OutBuffers[0].pvBuffer&&OutBuffers[0].cbBuffer)||(!OutBuffers[0].pvBuffer&&!OutBuffers[0].cbBuffer)); //отсылаем только если есть что отсылать if(OutBuffers[0].pvBuffer&&OutBuffers[0].cbBuffer){ //ASSERT(OutBuffers[0].pvBuffer); //ASSERT(OutBuffers[0].cbBuffer); //WS: отправим обработанные SCHANNEL данные SockByteStream->RawSend(OutBuffers[0].pvBuffer, OutBuffers[0].cbBuffer); //SSPI:освободим выделенную SCHANNEL память FreeContextBuffer(OutBuffers[0].pvBuffer); } //OutBuffers[0].BufferType=SECBUFFER_EMPTY; OutBuffers[0].pvBuffer=0; OutBuffers[0].cbBuffer=0;//нет необходимости do{ //ASSERT(SockDataBuf.size()>SockDataSize); //WS:получим ответ сервера (или его часть) if(!WasExtra){ SockDataSize+= SockByteStream->RawRecv(&SockDataBuf[SockDataSize], SockDataBuf.size()-SockDataSize); } else{ //пропустим 1 получение данных, т.к. в SECBUFFER_EXTRA может быть полный пакет, //и как следствие сервер ничего уже посылать не будет. //если же пакет все же не полный то получим SEC_E_INCOMPLETE_MESSAGE, //и просто выполним лишнюю итерацию. WasExtra=false; } //SSPI:передадим этот ответ в InitializeSecurityContext, и в случае если он скажет что надо еще данных - //опять запросим данные с сервера. и так до тех пор пока SCHANNEL не скажет "хватит". InBuffers[0].BufferType = SECBUFFER_TOKEN; InBuffers[0].pvBuffer = &SockDataBuf[0]; InBuffers[0].cbBuffer = SockDataSize; InBuffers[1].BufferType = SECBUFFER_EMPTY; InBuffers[1].pvBuffer = NULL; InBuffers[1].cbBuffer = 0; sec_s = InitializeSecurityContext(&m_hUserCred, &m_hContext, const_cast<TCHAR*>(TargetName), m_ReqContextAttr, 0, 0, &InBufferDesc, 0, 0, &OutBufferDesc, &m_ContextAttr, &m_ContextExpiry); }while(SEC_E_INCOMPLETE_MESSAGE==sec_s); //ASSERT(SEC_E_OK==sec_s||SEC_I_CONTINUE_NEEDED==sec_s); //может быть SECBUFFER_EXTRA //ASSERT(SECBUFFER_EXTRA!=InBuffers[0].BufferType);//такого вроде не должно быть if(SECBUFFER_EXTRA==InBuffers[1].BufferType){ WasExtra=true; if(SEC_I_CONTINUE_NEEDED==sec_s){ //Handshake еще не завершен. просто сервер выслал больше данных чем нужно было на данном шаге. //переносим эти данные на следующую итерацию memmove(&SockDataBuf[0], ((BYTE*)InBuffers[0].pvBuffer)+InBuffers[0].cbBuffer-InBuffers[1].cbBuffer, InBuffers[1].cbBuffer); SockDataSize=InBuffers[1].cbBuffer; } else{ //если Handshake уже завершен, значит SECBUFFER_EXTRA относится уже к основному протоколу обмена. //значит нужно сохранить эту информацию во временном хранилище. m_HandshakeExtra.insert(m_HandshakeExtra.end(), ((BYTE*)InBuffers[0].pvBuffer)+InBuffers[0].cbBuffer-InBuffers[1].cbBuffer, ((BYTE*)InBuffers[0].pvBuffer)+InBuffers[0].cbBuffer); SockDataSize=0; } } else{ SockDataSize=0; } } //ASSERT(0==OutBuffers[0].pvBuffer);//по идее не должно быть выделенной памяти. }
/* sqConnectSSL: Start/continue an SSL client handshake. Arguments: handle - the SSL handle srcBuf - the input token sent by the remote peer srcLen - the size of the input token dstBuf - the output buffer for a new token dstLen - the size of the output buffer Returns: The size of the output token or an error code. */ sqInt sqConnectSSL(sqInt handle, char* srcBuf, sqInt srcLen, char *dstBuf, sqInt dstLen) { SecBufferDesc *sbdIn = NULL; SECURITY_STATUS ret; SCHANNEL_CRED sc_cred = { 0 }; ULONG sslFlags, retFlags; sqSSL *ssl = sslFromHandle(handle); /* Verify state of session */ if(ssl == NULL || (ssl->state != SQSSL_UNUSED && ssl->state != SQSSL_CONNECTING)) { return SQSSL_INVALID_STATE; } if(ssl->dataLen + srcLen > ssl->dataMax) { /* resize the data buffer */ ssl->dataMax += (srcLen < 4096) ? (4096) : (srcLen+1024); ssl->dataBuf = realloc(ssl->dataBuf, ssl->dataMax); if(!ssl->dataBuf) return SQSSL_OUT_OF_MEMORY; } if(ssl->loglevel) printf("sqConnectSSL: input token %d bytes\n", srcLen); memcpy(ssl->dataBuf + ssl->dataLen, srcBuf, srcLen); ssl->dataLen += srcLen; /* Standard flags for SSL connection */ sslFlags = ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_CONFIDENTIALITY | ISC_REQ_EXTENDED_ERROR | ISC_REQ_INTEGRITY | ISC_REQ_REPLAY_DETECT | ISC_REQ_STREAM | ISC_REQ_MANUAL_CRED_VALIDATION; /* Set up the input and output buffers */ ssl->inbuf[0].BufferType = SECBUFFER_TOKEN; ssl->inbuf[0].cbBuffer = ssl->dataLen; ssl->inbuf[0].pvBuffer = ssl->dataBuf; ssl->inbuf[1].BufferType = SECBUFFER_EMPTY; ssl->inbuf[1].cbBuffer = 0; ssl->inbuf[1].pvBuffer = NULL; ssl->inbuf[2].BufferType = SECBUFFER_EMPTY; ssl->inbuf[2].cbBuffer = 0; ssl->inbuf[2].pvBuffer = NULL; ssl->inbuf[3].BufferType = SECBUFFER_EMPTY; ssl->inbuf[3].cbBuffer = 0; ssl->inbuf[3].pvBuffer = NULL; ssl->sbdIn.cBuffers = 4; ssl->outbuf[0].BufferType = SECBUFFER_EMPTY; ssl->outbuf[0].cbBuffer = 0; ssl->outbuf[0].pvBuffer = NULL; ssl->outbuf[1].BufferType = SECBUFFER_EMPTY; ssl->outbuf[1].cbBuffer = 0; ssl->outbuf[1].pvBuffer = NULL; ssl->sbdOut.cBuffers = 2; if(ssl->loglevel) printf("sqConnectSSL: Input to InitSecCtxt is %d bytes\n", ssl->dataLen); if(ssl->state == SQSSL_UNUSED) { ssl->state = SQSSL_CONNECTING; if(!sqSetupCert(ssl, ssl->certName, 0)) /* FIXME. We need a different error code here. */ return SQSSL_GENERIC_ERROR; ret = InitializeSecurityContext(&ssl->sslCred, NULL, NULL, sslFlags, 0, 0, NULL, 0, &ssl->sslCtxt, &ssl->sbdOut, &retFlags, NULL); } else { ret = InitializeSecurityContext(&ssl->sslCred, &ssl->sslCtxt, NULL, sslFlags, 0, 0, &ssl->sbdIn, 0, NULL, &ssl->sbdOut, &retFlags, NULL); } if(ssl->loglevel) printf("InitializeSecurityContext returned: %x\n", ret); if(ssl->loglevel) sqPrintSBD("Input Buffers:", ssl->sbdIn); if(ssl->loglevel) sqPrintSBD("Output Buffers:", ssl->sbdOut); if(ret != SEC_E_OK) { int count; /* Handle various failure conditions */ switch(ret) { case SEC_E_INCOMPLETE_MESSAGE: /* not enough data for the handshake to complete */ return SQSSL_NEED_MORE_DATA; case SEC_I_CONTINUE_NEEDED: /* Send contents back to peer and come back with more data */ count = sqCopyDescToken(ssl, ssl->sbdOut, dstBuf, dstLen); /* Sanity checks for buffers */ if(ssl->inbuf[0].BufferType != SECBUFFER_TOKEN) { if(ssl->loglevel) printf("sqConnectSSL: Unexpected buffer[0].BufferType -- %d\n", ssl->inbuf[0].BufferType); } if(ssl->inbuf[2].BufferType != SECBUFFER_EMPTY) { if(ssl->loglevel) printf("sqConnectSSL: Unexpected buffer[2].BufferType -- %d\n", ssl->inbuf[0].BufferType); } /* If there is SECBUFFER_EXTRA in the input we need to retain it */ if(ssl->inbuf[1].BufferType == SECBUFFER_EXTRA) { int extra = ssl->inbuf[1].cbBuffer; if(ssl->loglevel) printf("sqConnectSSL: Retaining %d token bytes\n", extra); memmove(ssl->dataBuf, ssl->dataBuf + (ssl->dataLen - extra), extra); ssl->dataLen = extra; } else ssl->dataLen = 0; /* Don't return zero (SQSSL_OK) when more data is needed */ return count ? count : SQSSL_NEED_MORE_DATA; default: if(ssl->loglevel) printf("Unexpected return code %d\n", ret); return SQSSL_GENERIC_ERROR; } } /* TODO: Look at retFlags */ ssl->state = SQSSL_CONNECTED; /* If there is SECBUFFER_EXTRA in the input we need to retain it */ if(ssl->inbuf[1].BufferType == SECBUFFER_EXTRA) { int extra = ssl->inbuf[1].cbBuffer; if(ssl->loglevel) printf("sqConnectSSL: Retaining %d token bytes\n", extra); memmove(ssl->dataBuf, ssl->dataBuf + (ssl->dataLen - extra), extra); ssl->dataLen = extra; } else { sqCopyExtraData(ssl, ssl->sbdOut); } ret = QueryContextAttributes(&ssl->sslCtxt, SECPKG_ATTR_STREAM_SIZES, &ssl->sslSizes); if(ssl->loglevel) printf("sqConnectSSL: Maximum message size is %d bytes\n", ssl->sslSizes.cbMaximumMessage); /* Extract the peer name */ sqExtractPeerName(ssl); /* Verify the certificate (sets certFlags) */ sqVerifyCert(ssl, false); return SQSSL_OK; }
static void on_underlying_io_bytes_received(void* context, const unsigned char* buffer, size_t size) { TLS_IO_INSTANCE* tls_io_instance = (TLS_IO_INSTANCE*)context; if (resize_receive_buffer(tls_io_instance, tls_io_instance->received_byte_count + size) == 0) { memcpy(tls_io_instance->received_bytes + tls_io_instance->received_byte_count, buffer, size); tls_io_instance->received_byte_count += size; if (size > tls_io_instance->needed_bytes) { tls_io_instance->needed_bytes = 0; } else { tls_io_instance->needed_bytes -= size; } switch (tls_io_instance->tlsio_state) { default: break; case TLSIO_STATE_ERROR: break; case TLSIO_STATE_HANDSHAKE_CLIENT_HELLO_SENT: { if (tls_io_instance->needed_bytes == 0) { SecBuffer input_buffers[2]; SecBuffer output_buffers[2]; ULONG context_attributes; /* we need to try and perform the second (next) step of the init */ input_buffers[0].cbBuffer = tls_io_instance->received_byte_count; input_buffers[0].BufferType = SECBUFFER_TOKEN; input_buffers[0].pvBuffer = (void*)tls_io_instance->received_bytes; input_buffers[1].cbBuffer = 0; input_buffers[1].BufferType = SECBUFFER_EMPTY; input_buffers[1].pvBuffer = 0; SecBufferDesc input_buffers_desc; input_buffers_desc.cBuffers = 2; input_buffers_desc.pBuffers = input_buffers; input_buffers_desc.ulVersion = SECBUFFER_VERSION; output_buffers[0].cbBuffer = 0; output_buffers[0].BufferType = SECBUFFER_TOKEN; output_buffers[0].pvBuffer = NULL; output_buffers[1].cbBuffer = 0; output_buffers[1].BufferType = SECBUFFER_EMPTY; output_buffers[1].pvBuffer = 0; SecBufferDesc output_buffers_desc; output_buffers_desc.cBuffers = 2; output_buffers_desc.pBuffers = output_buffers; output_buffers_desc.ulVersion = SECBUFFER_VERSION; SECURITY_STATUS status = InitializeSecurityContext(&tls_io_instance->credential_handle, &tls_io_instance->security_context, (SEC_CHAR*)tls_io_instance->host_name, ISC_REQ_EXTENDED_ERROR | ISC_REQ_STREAM | ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_USE_SUPPLIED_CREDS, 0, 0, &input_buffers_desc, 0, &tls_io_instance->security_context, &output_buffers_desc, &context_attributes, NULL); switch (status) { case SEC_E_INCOMPLETE_MESSAGE: if (input_buffers[1].BufferType != SECBUFFER_MISSING) { tls_io_instance->tlsio_state = TLSIO_STATE_ERROR; if (tls_io_instance->on_io_open_complete != NULL) { tls_io_instance->on_io_open_complete(tls_io_instance->open_callback_context, IO_OPEN_ERROR); } } else { tls_io_instance->needed_bytes = input_buffers[1].cbBuffer; tls_io_instance->consumed_bytes += tls_io_instance->needed_bytes; if (resize_receive_buffer(tls_io_instance, tls_io_instance->received_byte_count + tls_io_instance->needed_bytes) != 0) { tls_io_instance->tlsio_state = TLSIO_STATE_ERROR; if (tls_io_instance->on_io_open_complete != NULL) { tls_io_instance->on_io_open_complete(tls_io_instance->open_callback_context, IO_OPEN_ERROR); } } } break; case SEC_E_OK: memmove(tls_io_instance->received_bytes, tls_io_instance->received_bytes + tls_io_instance->consumed_bytes, tls_io_instance->received_byte_count - tls_io_instance->consumed_bytes); tls_io_instance->received_byte_count -= tls_io_instance->consumed_bytes; tls_io_instance->needed_bytes = 1; tls_io_instance->consumed_bytes = tls_io_instance->needed_bytes; if (set_receive_buffer(tls_io_instance, tls_io_instance->needed_bytes + tls_io_instance->received_byte_count) != 0) { tls_io_instance->tlsio_state = TLSIO_STATE_ERROR; if (tls_io_instance->on_io_open_complete != NULL) { tls_io_instance->on_io_open_complete(tls_io_instance->open_callback_context, IO_OPEN_ERROR); } } else { tls_io_instance->tlsio_state = TLSIO_STATE_OPEN; if (tls_io_instance->on_io_open_complete != NULL) { tls_io_instance->on_io_open_complete(tls_io_instance->open_callback_context, IO_OPEN_OK); } } break; case SEC_I_COMPLETE_NEEDED: case SEC_I_CONTINUE_NEEDED: case SEC_I_COMPLETE_AND_CONTINUE: if ((output_buffers[0].cbBuffer > 0) && xio_send(tls_io_instance->socket_io, output_buffers[0].pvBuffer, output_buffers[0].cbBuffer, NULL, NULL) != 0) { tls_io_instance->tlsio_state = TLSIO_STATE_ERROR; if (tls_io_instance->on_io_open_complete != NULL) { tls_io_instance->on_io_open_complete(tls_io_instance->open_callback_context, IO_OPEN_ERROR); } } else { (void)memmove(tls_io_instance->received_bytes, tls_io_instance->received_bytes + tls_io_instance->consumed_bytes, tls_io_instance->received_byte_count - tls_io_instance->consumed_bytes); tls_io_instance->received_byte_count -= tls_io_instance->consumed_bytes; /* set the needed bytes to 1, to get on the next byte how many we actually need */ tls_io_instance->needed_bytes = 1; tls_io_instance->consumed_bytes = tls_io_instance->needed_bytes; if (set_receive_buffer(tls_io_instance, tls_io_instance->needed_bytes + tls_io_instance->received_byte_count) != 0) { FreeCredentialHandle(&tls_io_instance->credential_handle); tls_io_instance->tlsio_state = TLSIO_STATE_ERROR; if (tls_io_instance->on_io_open_complete != NULL) { tls_io_instance->on_io_open_complete(tls_io_instance->open_callback_context, IO_OPEN_ERROR); } } else { tls_io_instance->tlsio_state = TLSIO_STATE_HANDSHAKE_CLIENT_HELLO_SENT; } } break; } } break; case TLSIO_STATE_OPEN: { if (tls_io_instance->needed_bytes == 0) { SecBuffer security_buffers[4]; SecBufferDesc security_buffers_desc; security_buffers[0].BufferType = SECBUFFER_DATA; security_buffers[0].pvBuffer = tls_io_instance->received_bytes; security_buffers[0].cbBuffer = tls_io_instance->received_byte_count; security_buffers[1].BufferType = SECBUFFER_EMPTY; security_buffers[2].BufferType = SECBUFFER_EMPTY; security_buffers[3].BufferType = SECBUFFER_EMPTY; security_buffers_desc.cBuffers = sizeof(security_buffers) / sizeof(security_buffers[0]); security_buffers_desc.pBuffers = security_buffers; security_buffers_desc.ulVersion = SECBUFFER_VERSION; SECURITY_STATUS status = DecryptMessage(&tls_io_instance->security_context, &security_buffers_desc, 0, NULL); switch (status) { case SEC_E_INCOMPLETE_MESSAGE: if (security_buffers[1].BufferType != SECBUFFER_MISSING) { tls_io_instance->tlsio_state = TLSIO_STATE_ERROR; indicate_error(tls_io_instance); } else { tls_io_instance->needed_bytes = security_buffers[1].cbBuffer; tls_io_instance->consumed_bytes += tls_io_instance->needed_bytes; if (resize_receive_buffer(tls_io_instance, tls_io_instance->received_byte_count + tls_io_instance->needed_bytes) != 0) { tls_io_instance->tlsio_state = TLSIO_STATE_ERROR; indicate_error(tls_io_instance); } } break; case SEC_E_OK: if (security_buffers[1].BufferType != SECBUFFER_DATA) { tls_io_instance->tlsio_state = TLSIO_STATE_ERROR; indicate_error(tls_io_instance); } else { size_t i; for (i = 0; i < security_buffers[1].cbBuffer; i++) { LOG(tls_io_instance->logger_log, 0, "<-%02x ", ((unsigned char*)security_buffers[1].pvBuffer)[i]); } /* notify of the received data */ if (tls_io_instance->on_bytes_received != NULL) { tls_io_instance->on_bytes_received(tls_io_instance->open_callback_context, security_buffers[1].pvBuffer, security_buffers[1].cbBuffer); } (void)memmove(tls_io_instance->received_bytes, tls_io_instance->received_bytes + tls_io_instance->consumed_bytes, tls_io_instance->received_byte_count - tls_io_instance->consumed_bytes); tls_io_instance->received_byte_count -= tls_io_instance->consumed_bytes; tls_io_instance->needed_bytes = 1; tls_io_instance->consumed_bytes = tls_io_instance->needed_bytes; if (set_receive_buffer(tls_io_instance, tls_io_instance->needed_bytes + tls_io_instance->received_byte_count) != 0) { tls_io_instance->tlsio_state = TLSIO_STATE_ERROR; indicate_error(tls_io_instance); } } break; } } break; } } } } }
static SECURITY_STATUS SchannelClientHandshakeLoop( SOCKET Socket, /* in */ PCredHandle phCreds, /* in */ CtxtHandle *phContext, /* i-o */ BOOL fDoInitialRead, /* in */ SecBuffer *pExtraData) /* out */ { SecBufferDesc InBuffer; SecBuffer InBuffers[2]; SecBufferDesc OutBuffer; SecBuffer OutBuffers[1]; DWORD dwSSPIFlags; DWORD dwSSPIOutFlags; TimeStamp tsExpiry; SECURITY_STATUS scRet; DWORD cbData; PUCHAR IoBuffer; DWORD cbIoBuffer; BOOL fDoRead; int retry_count; dwSSPIFlags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT | ISC_REQ_CONFIDENTIALITY | ISC_RET_EXTENDED_ERROR | ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM; /* * Allocate data buffer. */ IoBuffer = malloc(IO_BUFFER_SIZE); if (IoBuffer == NULL) { mylog("**** Out of memory (1)\n"); return SEC_E_INTERNAL_ERROR; } cbIoBuffer = 0; fDoRead = fDoInitialRead; /* * Loop until the handshake is finished or an error occurs. */ retry_count = 0; scRet = SEC_I_CONTINUE_NEEDED; while (scRet == SEC_I_CONTINUE_NEEDED || scRet == SEC_E_INCOMPLETE_MESSAGE || scRet == SEC_I_INCOMPLETE_CREDENTIALS) { /* * Read data from server. */ if( 0 == cbIoBuffer || scRet == SEC_E_INCOMPLETE_MESSAGE) { if (fDoRead) { cbData = recv(Socket, IoBuffer + cbIoBuffer, IO_BUFFER_SIZE - cbIoBuffer, 0); if (cbData == SOCKET_ERROR) { int gerrno = SOCK_ERRNO; mylog("**** Error %d reading data from server\n", gerrno); switch (gerrno) { case EINTR: continue; case ECONNRESET: break; case EWOULDBLOCK: retry_count++; if (Socket_wait_for_ready(Socket, FALSE, retry_count) >= 0) continue; default: scRet = SEC_E_INTERNAL_ERROR; break; } break; } else if(cbData == 0) { mylog("**** Server unexpectedly disconnected\n"); scRet = SEC_E_INTERNAL_ERROR; break; } mylog("%d bytes of handshake data received\n", cbData); cbIoBuffer += cbData; retry_count = 0; } else { fDoRead = TRUE; } } /* * Set up the input buffers. Buffer 0 is used to pass in data * received from the server. Schannel will consume some or all * of this. Leftover data (if any) will be placed in buffer 1 and * given a buffer type of SECBUFFER_EXTRA. */ InBuffers[0].pvBuffer = IoBuffer; InBuffers[0].cbBuffer = cbIoBuffer; InBuffers[0].BufferType = SECBUFFER_TOKEN; InBuffers[1].pvBuffer = NULL; InBuffers[1].cbBuffer = 0; InBuffers[1].BufferType = SECBUFFER_EMPTY; InBuffer.cBuffers = 2; InBuffer.pBuffers = InBuffers; InBuffer.ulVersion = SECBUFFER_VERSION; /* * Set up the output buffers. These are initialized to NULL * so as to make it less likely we'll attempt to free random * garbage later. */ OutBuffers[0].pvBuffer = NULL; OutBuffers[0].BufferType= SECBUFFER_TOKEN; OutBuffers[0].cbBuffer = 0; OutBuffer.cBuffers = 1; OutBuffer.pBuffers = OutBuffers; OutBuffer.ulVersion = SECBUFFER_VERSION; /* * Call InitializeSecurityContext. */ scRet = InitializeSecurityContext(phCreds, phContext, NULL, dwSSPIFlags, 0, SECURITY_NATIVE_DREP, &InBuffer, 0, NULL, &OutBuffer, &dwSSPIOutFlags, &tsExpiry); /* * If InitializeSecurityContext was successful (or if the error was * one of the special extended ones), send the contends of the output * buffer to the server. */ if( scRet == SEC_E_OK || scRet == SEC_I_CONTINUE_NEEDED || FAILED(scRet) && (dwSSPIOutFlags & ISC_RET_EXTENDED_ERROR)) { if (OutBuffers[0].cbBuffer != 0 && OutBuffers[0].pvBuffer != NULL) { cbData = sendall(Socket, OutBuffers[0].pvBuffer, OutBuffers[0].cbBuffer); if (cbData == SOCKET_ERROR || cbData == 0) { mylog("**** Error %d sending data to server (2)\n", SOCK_ERRNO); FreeContextBuffer(OutBuffers[0].pvBuffer); DeleteSecurityContext(phContext); return SEC_E_INTERNAL_ERROR; } mylog("%d bytes of handshake data sent\n", cbData); /* Free output buffer. */ FreeContextBuffer(OutBuffers[0].pvBuffer); OutBuffers[0].pvBuffer = NULL; } } /* * If InitializeSecurityContext returned SEC_E_INCOMPLETE_MESSAGE, * then we need to read more data from the server and try again. */ if (scRet == SEC_E_INCOMPLETE_MESSAGE) { continue; } /* * If InitializeSecurityContext returned SEC_E_OK, then the * handshake completed successfully. */ if(scRet == SEC_E_OK) { /* * If the "extra" buffer contains data, this is encrypted application * protocol layer stuff. It needs to be saved. The application layer * will later decrypt it with DecryptMessage. */ mylog("Handshake was successful\n"); if (InBuffers[1].BufferType == SECBUFFER_EXTRA) { pExtraData->pvBuffer = malloc(InBuffers[1].cbBuffer); if (pExtraData->pvBuffer == NULL) { mylog("**** Out of memory (2)\n"); return SEC_E_INTERNAL_ERROR; } memmove(pExtraData->pvBuffer, IoBuffer + (cbIoBuffer - InBuffers[1].cbBuffer), InBuffers[1].cbBuffer); pExtraData->cbBuffer = InBuffers[1].cbBuffer; pExtraData->BufferType = SECBUFFER_TOKEN; mylog("%d bytes of app data was bundled with handshake data\n", pExtraData->cbBuffer); } else { pExtraData->pvBuffer = NULL; pExtraData->cbBuffer = 0; pExtraData->BufferType = SECBUFFER_EMPTY; } /* * Bail out to quit */ break; } /* * Check for fatal error. */ if(FAILED(scRet)) { mylog("**** Error 0x%p returned by InitializeSecurityContext (2)\n", scRet); break; } /* * If InitializeSecurityContext returned SEC_I_INCOMPLETE_CREDENTIALS, * then the server just requested client authentication. */ if (scRet == SEC_I_INCOMPLETE_CREDENTIALS) { /* * Busted. The server has requested client authentication and * the credential we supplied didn't contain a client certificate. * * * This function will read the list of trusted certificate * authorities ("issuers") that was received from the server * and attempt to find a suitable client certificate that * was issued by one of these. If this function is successful, * then we will connect using the new certificate. Otherwise, * we will attempt to connect anonymously (using our current * credentials). */ GetNewSchannelClientCredentials(phCreds, phContext); /* Go around again. */ fDoRead = FALSE; scRet = SEC_I_CONTINUE_NEEDED; continue; } /* * Copy any leftover data from the "extra" buffer, and go around * again. */ if ( InBuffers[1].BufferType == SECBUFFER_EXTRA ) { memmove(IoBuffer, IoBuffer + (cbIoBuffer - InBuffers[1].cbBuffer), InBuffers[1].cbBuffer); cbIoBuffer = InBuffers[1].cbBuffer; } else { cbIoBuffer = 0; } } /* Delete the security context in the case of a fatal error. */ if (FAILED(scRet)) { DeleteSecurityContext(phContext); } free(IoBuffer); return scRet; }
SECURITY_STATUS ma_schannel_client_handshake(MARIADB_TLS *ctls) { MARIADB_PVIO *pvio; SECURITY_STATUS sRet; DWORD OutFlags; DWORD r; SC_CTX *sctx; SecBuffer ExtraData; DWORD SFlags= ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT | ISC_REQ_CONFIDENTIALITY | ISC_RET_EXTENDED_ERROR | ISC_REQ_USE_SUPPLIED_CREDS | ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM; SecBufferDesc BufferOut; SecBuffer BuffersOut; if (!ctls || !ctls->pvio) return 1; pvio= ctls->pvio; sctx= (SC_CTX *)ctls->ssl; /* Initialie securifty context */ BuffersOut.BufferType= SECBUFFER_TOKEN; BuffersOut.cbBuffer= 0; BuffersOut.pvBuffer= NULL; BufferOut.cBuffers= 1; BufferOut.pBuffers= &BuffersOut; BufferOut.ulVersion= SECBUFFER_VERSION; sRet = InitializeSecurityContext(&sctx->CredHdl, NULL, pvio->mysql->host, SFlags, 0, SECURITY_NATIVE_DREP, NULL, 0, &sctx->ctxt, &BufferOut, &OutFlags, NULL); if(sRet != SEC_I_CONTINUE_NEEDED) { ma_schannel_set_sec_error(pvio, sRet); return sRet; } /* send client hello packaet */ if(BuffersOut.cbBuffer != 0 && BuffersOut.pvBuffer != NULL) { r= (DWORD)pvio->methods->write(pvio, (uchar *)BuffersOut.pvBuffer, (size_t)BuffersOut.cbBuffer); if (r <= 0) { sRet= SEC_E_INTERNAL_ERROR; goto end; } } sRet= ma_schannel_handshake_loop(pvio, TRUE, &ExtraData); /* allocate IO-Buffer for write operations: After handshake was successfull, we are able now to calculate payload */ if ((sRet = QueryContextAttributes(&sctx->ctxt, SECPKG_ATTR_STREAM_SIZES, &sctx->Sizes ))) goto end; sctx->IoBufferSize= SCHANNEL_PAYLOAD(sctx->Sizes); if (!(sctx->IoBuffer= (PUCHAR)LocalAlloc(0, sctx->IoBufferSize))) { sRet= SEC_E_INSUFFICIENT_MEMORY; goto end; } return sRet; end: LocalFree(sctx->IoBuffer); sctx->IoBufferSize= 0; FreeContextBuffer(BuffersOut.pvBuffer); DeleteSecurityContext(&sctx->ctxt); return sRet; }
apr_status_t serf__kerb_init_sec_context(serf__kerb_context_t *ctx, const char *service, const char *hostname, serf__kerb_buffer_t *input_buf, serf__kerb_buffer_t *output_buf, apr_pool_t *scratch_pool, apr_pool_t *result_pool ) { SECURITY_STATUS status; ULONG actual_attr; SecBuffer sspi_in_buffer; SecBufferDesc sspi_in_buffer_desc; SecBuffer sspi_out_buffer; SecBufferDesc sspi_out_buffer_desc; char *target_name; apr_status_t apr_status; const char *canonname; apr_status = get_canonical_hostname(&canonname, hostname, scratch_pool); if (apr_status) { return apr_status; } target_name = apr_pstrcat(scratch_pool, service, "/", canonname, NULL); /* Prepare input buffer description. */ sspi_in_buffer.BufferType = SECBUFFER_TOKEN; sspi_in_buffer.pvBuffer = input_buf->value; sspi_in_buffer.cbBuffer = input_buf->length; sspi_in_buffer_desc.cBuffers = 1; sspi_in_buffer_desc.pBuffers = &sspi_in_buffer; sspi_in_buffer_desc.ulVersion = SECBUFFER_VERSION; /* Output buffers. Output buffer will be allocated by system. */ sspi_out_buffer.BufferType = SECBUFFER_TOKEN; sspi_out_buffer.pvBuffer = NULL; sspi_out_buffer.cbBuffer = 0; sspi_out_buffer_desc.cBuffers = 1; sspi_out_buffer_desc.pBuffers = &sspi_out_buffer; sspi_out_buffer_desc.ulVersion = SECBUFFER_VERSION; status = InitializeSecurityContext( &ctx->sspi_credentials, ctx->initalized ? &ctx->sspi_context : NULL, target_name, ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_MUTUAL_AUTH | ISC_REQ_CONFIDENTIALITY, 0, /* Reserved1 */ SECURITY_NETWORK_DREP, &sspi_in_buffer_desc, 0, /* Reserved2 */ &ctx->sspi_context, &sspi_out_buffer_desc, &actual_attr, NULL); if (sspi_out_buffer.cbBuffer > 0) { apr_pool_cleanup_register(result_pool, sspi_out_buffer.pvBuffer, cleanup_sec_buffer, apr_pool_cleanup_null); } ctx->initalized = TRUE; /* Finish authentication if SSPI requires so. */ if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) { CompleteAuthToken(&ctx->sspi_context, &sspi_out_buffer_desc); } output_buf->value = sspi_out_buffer.pvBuffer; output_buf->length = sspi_out_buffer.cbBuffer; switch(status) { case SEC_I_COMPLETE_AND_CONTINUE: case SEC_I_CONTINUE_NEEDED: return APR_EAGAIN; case SEC_I_COMPLETE_NEEDED: case SEC_E_OK: return APR_SUCCESS; default: return map_sspi_status(status); } }
static void on_underlying_io_bytes_received(void* context, const unsigned char* buffer, size_t size) { TLS_IO_INSTANCE* tls_io_instance = (TLS_IO_INSTANCE*)context; size_t consumed_bytes; LOG(tls_io_instance->logger_log, LOG_LINE, "%d received on tls_schannel", size); if (resize_receive_buffer(tls_io_instance, tls_io_instance->received_byte_count + size) == 0) { memcpy(tls_io_instance->received_bytes + tls_io_instance->received_byte_count, buffer, size); tls_io_instance->received_byte_count += size; if (size > tls_io_instance->needed_bytes) { tls_io_instance->needed_bytes = 0; } else { tls_io_instance->needed_bytes -= size; } /* Drain what we received */ while (tls_io_instance->needed_bytes == 0) { if (tls_io_instance->tlsio_state == TLSIO_STATE_HANDSHAKE_CLIENT_HELLO_SENT) { SecBuffer input_buffers[2]; SecBuffer output_buffers[2]; ULONG context_attributes; /* we need to try and perform the second (next) step of the init */ input_buffers[0].cbBuffer = tls_io_instance->received_byte_count; input_buffers[0].BufferType = SECBUFFER_TOKEN; input_buffers[0].pvBuffer = (void*)tls_io_instance->received_bytes; input_buffers[1].cbBuffer = 0; input_buffers[1].BufferType = SECBUFFER_EMPTY; input_buffers[1].pvBuffer = 0; SecBufferDesc input_buffers_desc; input_buffers_desc.cBuffers = 2; input_buffers_desc.pBuffers = input_buffers; input_buffers_desc.ulVersion = SECBUFFER_VERSION; output_buffers[0].cbBuffer = 0; output_buffers[0].BufferType = SECBUFFER_TOKEN; output_buffers[0].pvBuffer = NULL; output_buffers[1].cbBuffer = 0; output_buffers[1].BufferType = SECBUFFER_EMPTY; output_buffers[1].pvBuffer = 0; SecBufferDesc output_buffers_desc; output_buffers_desc.cBuffers = 2; output_buffers_desc.pBuffers = output_buffers; output_buffers_desc.ulVersion = SECBUFFER_VERSION; unsigned long flags = ISC_REQ_EXTENDED_ERROR | ISC_REQ_STREAM | ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_USE_SUPPLIED_CREDS; SECURITY_STATUS status = InitializeSecurityContext(&tls_io_instance->credential_handle, &tls_io_instance->security_context, (SEC_CHAR*)tls_io_instance->host_name, flags, 0, 0, &input_buffers_desc, 0, &tls_io_instance->security_context, &output_buffers_desc, &context_attributes, NULL); switch (status) { case SEC_E_INCOMPLETE_MESSAGE: if (input_buffers[1].BufferType != SECBUFFER_MISSING) { //If SECBUFFER_MISSING not sent, try to read byte by byte. tls_io_instance->needed_bytes = 1; } else { tls_io_instance->needed_bytes = input_buffers[1].cbBuffer; } if (resize_receive_buffer(tls_io_instance, tls_io_instance->received_byte_count + tls_io_instance->needed_bytes) != 0) { tls_io_instance->tlsio_state = TLSIO_STATE_ERROR; if (tls_io_instance->on_io_open_complete != NULL) { tls_io_instance->on_io_open_complete(tls_io_instance->on_io_open_complete_context, IO_OPEN_ERROR); } } break; case SEC_E_OK: consumed_bytes = tls_io_instance->received_byte_count; /* Any extra bytes left over or did we fully consume the receive buffer? */ if (input_buffers[1].BufferType == SECBUFFER_EXTRA) { consumed_bytes -= input_buffers[1].cbBuffer; (void)memmove(tls_io_instance->received_bytes, tls_io_instance->received_bytes + consumed_bytes, tls_io_instance->received_byte_count - consumed_bytes); } tls_io_instance->received_byte_count -= consumed_bytes; /* if nothing more to consume, set the needed bytes to 1, to get on the next byte how many we actually need */ tls_io_instance->needed_bytes = tls_io_instance->received_byte_count == 0 ? 1 : 0; if (set_receive_buffer(tls_io_instance, tls_io_instance->needed_bytes + tls_io_instance->received_byte_count) != 0) { tls_io_instance->tlsio_state = TLSIO_STATE_ERROR; if (tls_io_instance->on_io_open_complete != NULL) { tls_io_instance->on_io_open_complete(tls_io_instance->on_io_open_complete_context, IO_OPEN_ERROR); } } else { tls_io_instance->tlsio_state = TLSIO_STATE_OPEN; if (tls_io_instance->on_io_open_complete != NULL) { tls_io_instance->on_io_open_complete(tls_io_instance->on_io_open_complete_context, IO_OPEN_OK); } } break; case SEC_I_COMPLETE_NEEDED: case SEC_I_CONTINUE_NEEDED: case SEC_I_COMPLETE_AND_CONTINUE: if ((output_buffers[0].cbBuffer > 0) && xio_send(tls_io_instance->socket_io, output_buffers[0].pvBuffer, output_buffers[0].cbBuffer, NULL, NULL) != 0) { tls_io_instance->tlsio_state = TLSIO_STATE_ERROR; if (tls_io_instance->on_io_open_complete != NULL) { tls_io_instance->on_io_open_complete(tls_io_instance->on_io_open_complete_context, IO_OPEN_ERROR); } } else { consumed_bytes = tls_io_instance->received_byte_count; /* Any extra bytes left over or did we fully consume the receive buffer? */ if (input_buffers[1].BufferType == SECBUFFER_EXTRA) { consumed_bytes -= input_buffers[1].cbBuffer; (void)memmove(tls_io_instance->received_bytes, tls_io_instance->received_bytes + consumed_bytes, tls_io_instance->received_byte_count - consumed_bytes); } tls_io_instance->received_byte_count -= consumed_bytes; /* if nothing more to consume, set the needed bytes to 1, to get on the next byte how many we actually need */ tls_io_instance->needed_bytes = tls_io_instance->received_byte_count == 0 ? 1 : 0; if (set_receive_buffer(tls_io_instance, tls_io_instance->needed_bytes + tls_io_instance->received_byte_count) != 0) { tls_io_instance->tlsio_state = TLSIO_STATE_ERROR; if (tls_io_instance->on_io_open_complete != NULL) { tls_io_instance->on_io_open_complete(tls_io_instance->on_io_open_complete_context, IO_OPEN_ERROR); } } else { tls_io_instance->tlsio_state = TLSIO_STATE_HANDSHAKE_CLIENT_HELLO_SENT; } } break; case SEC_E_UNTRUSTED_ROOT: tls_io_instance->tlsio_state = TLSIO_STATE_ERROR; if (tls_io_instance->on_io_open_complete != NULL) { tls_io_instance->on_io_open_complete(tls_io_instance->on_io_open_complete_context, IO_OPEN_ERROR); } break; default: { LPVOID srcText = NULL; if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, status, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)srcText, 0, NULL) > 0) { LogError("[%#x] %s", status, (LPTSTR)srcText); LocalFree(srcText); } else { LogError("[%#x]", status); } tls_io_instance->tlsio_state = TLSIO_STATE_ERROR; indicate_error(tls_io_instance); } break; } } else if (tls_io_instance->tlsio_state == TLSIO_STATE_OPEN) { SecBuffer security_buffers[4]; SecBufferDesc security_buffers_desc; security_buffers[0].BufferType = SECBUFFER_DATA; security_buffers[0].pvBuffer = tls_io_instance->received_bytes; security_buffers[0].cbBuffer = tls_io_instance->received_byte_count; security_buffers[1].BufferType = SECBUFFER_EMPTY; security_buffers[2].BufferType = SECBUFFER_EMPTY; security_buffers[3].BufferType = SECBUFFER_EMPTY; security_buffers_desc.cBuffers = sizeof(security_buffers) / sizeof(security_buffers[0]); security_buffers_desc.pBuffers = security_buffers; security_buffers_desc.ulVersion = SECBUFFER_VERSION; SECURITY_STATUS status = DecryptMessage(&tls_io_instance->security_context, &security_buffers_desc, 0, NULL); switch (status) { case SEC_E_INCOMPLETE_MESSAGE: if (security_buffers[1].BufferType != SECBUFFER_MISSING) { //If SECBUFFER_MISSING not sent, try to read byte by byte. tls_io_instance->needed_bytes = 1; } else { tls_io_instance->needed_bytes = security_buffers[1].cbBuffer; } if (resize_receive_buffer(tls_io_instance, tls_io_instance->received_byte_count + tls_io_instance->needed_bytes) != 0) { tls_io_instance->tlsio_state = TLSIO_STATE_ERROR; indicate_error(tls_io_instance); } break; case SEC_E_OK: if (security_buffers[1].BufferType != SECBUFFER_DATA) { tls_io_instance->tlsio_state = TLSIO_STATE_ERROR; indicate_error(tls_io_instance); } else { size_t i; if (tls_io_instance->logger_log) { for (i = 0; i < security_buffers[1].cbBuffer; i++) { LOG(tls_io_instance->logger_log, 0, "-> %02x ", ((unsigned char*)security_buffers[1].pvBuffer)[i]); } LOG(tls_io_instance->logger_log, LOG_LINE, ""); } /* notify of the received data */ if (tls_io_instance->on_bytes_received != NULL) { tls_io_instance->on_bytes_received(tls_io_instance->on_bytes_received_context, security_buffers[1].pvBuffer, security_buffers[1].cbBuffer); } consumed_bytes = tls_io_instance->received_byte_count; LOG(tls_io_instance->logger_log, LOG_LINE, "%d consumed", tls_io_instance->received_byte_count); for (i = 0; i < sizeof(security_buffers) / sizeof(security_buffers[0]); i++) { /* Any extra bytes left over or did we fully consume the receive buffer? */ if (security_buffers[i].BufferType == SECBUFFER_EXTRA) { consumed_bytes -= security_buffers[i].cbBuffer; (void)memmove(tls_io_instance->received_bytes, tls_io_instance->received_bytes + consumed_bytes, tls_io_instance->received_byte_count - consumed_bytes); break; } } tls_io_instance->received_byte_count -= consumed_bytes; /* if nothing more to consume, set the needed bytes to 1, to get on the next byte how many we actually need */ tls_io_instance->needed_bytes = tls_io_instance->received_byte_count == 0 ? 1 : 0; if (set_receive_buffer(tls_io_instance, tls_io_instance->needed_bytes + tls_io_instance->received_byte_count) != 0) { tls_io_instance->tlsio_state = TLSIO_STATE_ERROR; indicate_error(tls_io_instance); } } break; default: { LPVOID srcText = NULL; if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, status, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)srcText, 0, NULL) > 0) { LogError("[%#x] %s", status, (LPTSTR)srcText); LocalFree(srcText); } else { LogError("[%#x]", status); } tls_io_instance->tlsio_state = TLSIO_STATE_ERROR; indicate_error(tls_io_instance); } break; } } else { /* Received data in error or other state */ break; } } } }
void SchannelContext::continueHandshake(const SafeByteArray& data) { appendNewData(data); while (!m_receivedData.empty()) { SecBuffer inBuffers[2]; // Provide Schannel with the remote host's handshake data inBuffers[0].pvBuffer = (char*)(&m_receivedData[0]); inBuffers[0].cbBuffer = (unsigned long)m_receivedData.size(); inBuffers[0].BufferType = SECBUFFER_TOKEN; inBuffers[1].pvBuffer = NULL; inBuffers[1].cbBuffer = 0; inBuffers[1].BufferType = SECBUFFER_EMPTY; SecBufferDesc inBufferDesc = {0}; inBufferDesc.cBuffers = 2; inBufferDesc.pBuffers = inBuffers; inBufferDesc.ulVersion = SECBUFFER_VERSION; SecBuffer outBuffers[2]; // We let Schannel allocate the output buffer for us outBuffers[0].pvBuffer = NULL; outBuffers[0].cbBuffer = 0; outBuffers[0].BufferType = SECBUFFER_TOKEN; // Contains alert data if an alert is generated outBuffers[1].pvBuffer = NULL; outBuffers[1].cbBuffer = 0; outBuffers[1].BufferType = SECBUFFER_ALERT; // Make sure the output buffers are freed ScopedSecBuffer scopedOutputData(&outBuffers[0]); ScopedSecBuffer scopedOutputAlertData(&outBuffers[1]); SecBufferDesc outBufferDesc = {0}; outBufferDesc.cBuffers = 2; outBufferDesc.pBuffers = outBuffers; outBufferDesc.ulVersion = SECBUFFER_VERSION; SECURITY_STATUS status = InitializeSecurityContext( m_credHandle, m_ctxtHandle, NULL, m_ctxtFlags, 0, 0, &inBufferDesc, 0, NULL, &outBufferDesc, &m_secContext, NULL); if (status == SEC_E_INCOMPLETE_MESSAGE) { // Wait for more data to arrive break; } else if (status == SEC_I_CONTINUE_NEEDED) { SecBuffer* pDataBuffer = &outBuffers[0]; SecBuffer* pExtraBuffer = &inBuffers[1]; if (pDataBuffer && pDataBuffer->cbBuffer > 0 && pDataBuffer->pvBuffer != NULL) sendDataOnNetwork(pDataBuffer->pvBuffer, pDataBuffer->cbBuffer); if (pExtraBuffer->BufferType == SECBUFFER_EXTRA) m_receivedData.erase(m_receivedData.begin(), m_receivedData.end() - pExtraBuffer->cbBuffer); else m_receivedData.clear(); break; } else if (status == SEC_E_OK) { status = validateServerCertificate(); if (status != SEC_E_OK) handleCertError(status); SecBuffer* pExtraBuffer = &inBuffers[1]; if (pExtraBuffer && pExtraBuffer->cbBuffer > 0) m_receivedData.erase(m_receivedData.begin(), m_receivedData.end() - pExtraBuffer->cbBuffer); else m_receivedData.clear(); m_state = Connected; determineStreamSizes(); onConnected(); } else { // We failed to initialize the security context handleCertError(status); indicateError(); return; } } }
static int tls_client_handshake_loop(URLContext *h, int initial) { TLSContext *c = h->priv_data; TLSShared *s = &c->tls_shared; SECURITY_STATUS sspi_ret; SecBuffer outbuf[3]; SecBufferDesc outbuf_desc; SecBuffer inbuf[2]; SecBufferDesc inbuf_desc; int i, ret = 0, read_data = initial; if (c->enc_buf == NULL) { c->enc_buf_offset = 0; ret = av_reallocp(&c->enc_buf, SCHANNEL_INITIAL_BUFFER_SIZE); if (ret < 0) goto fail; c->enc_buf_size = SCHANNEL_INITIAL_BUFFER_SIZE; } if (c->dec_buf == NULL) { c->dec_buf_offset = 0; ret = av_reallocp(&c->dec_buf, SCHANNEL_INITIAL_BUFFER_SIZE); if (ret < 0) goto fail; c->dec_buf_size = SCHANNEL_INITIAL_BUFFER_SIZE; } while (1) { if (c->enc_buf_size - c->enc_buf_offset < SCHANNEL_FREE_BUFFER_SIZE) { c->enc_buf_size = c->enc_buf_offset + SCHANNEL_FREE_BUFFER_SIZE; ret = av_reallocp(&c->enc_buf, c->enc_buf_size); if (ret < 0) { c->enc_buf_size = c->enc_buf_offset = 0; goto fail; } } if (read_data) { ret = ffurl_read(c->tls_shared.tcp, c->enc_buf + c->enc_buf_offset, c->enc_buf_size - c->enc_buf_offset); if (ret < 0) { av_log(h, AV_LOG_ERROR, "Failed to read handshake response\n"); goto fail; } c->enc_buf_offset += ret; } /* input buffers */ init_sec_buffer(&inbuf[0], SECBUFFER_TOKEN, av_malloc(c->enc_buf_offset), c->enc_buf_offset); init_sec_buffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0); init_sec_buffer_desc(&inbuf_desc, inbuf, 2); if (inbuf[0].pvBuffer == NULL) { av_log(h, AV_LOG_ERROR, "Failed to allocate input buffer\n"); ret = AVERROR(ENOMEM); goto fail; } memcpy(inbuf[0].pvBuffer, c->enc_buf, c->enc_buf_offset); /* output buffers */ init_sec_buffer(&outbuf[0], SECBUFFER_TOKEN, NULL, 0); init_sec_buffer(&outbuf[1], SECBUFFER_ALERT, NULL, 0); init_sec_buffer(&outbuf[2], SECBUFFER_EMPTY, NULL, 0); init_sec_buffer_desc(&outbuf_desc, outbuf, 3); sspi_ret = InitializeSecurityContext(&c->cred_handle, &c->ctxt_handle, s->host, c->request_flags, 0, 0, &inbuf_desc, 0, NULL, &outbuf_desc, &c->context_flags, &c->ctxt_timestamp); av_freep(&inbuf[0].pvBuffer); if (sspi_ret == SEC_E_INCOMPLETE_MESSAGE) { av_log(h, AV_LOG_DEBUG, "Received incomplete handshake, need more data\n"); read_data = 1; continue; } /* remote requests a client certificate - attempt to continue without one anyway */ if (sspi_ret == SEC_I_INCOMPLETE_CREDENTIALS && !(c->request_flags & ISC_REQ_USE_SUPPLIED_CREDS)) { av_log(h, AV_LOG_VERBOSE, "Client certificate has been requested, ignoring\n"); c->request_flags |= ISC_REQ_USE_SUPPLIED_CREDS; read_data = 0; continue; } /* continue handshake */ if (sspi_ret == SEC_I_CONTINUE_NEEDED || sspi_ret == SEC_E_OK) { for (i = 0; i < 3; i++) { if (outbuf[i].BufferType == SECBUFFER_TOKEN && outbuf[i].cbBuffer > 0) { ret = ffurl_write(c->tls_shared.tcp, outbuf[i].pvBuffer, outbuf[i].cbBuffer); if (ret < 0 || ret != outbuf[i].cbBuffer) { av_log(h, AV_LOG_VERBOSE, "Failed to send handshake data\n"); ret = AVERROR(EIO); goto fail; } } if (outbuf[i].pvBuffer != NULL) { FreeContextBuffer(outbuf[i].pvBuffer); outbuf[i].pvBuffer = NULL; } } } else { if (sspi_ret == SEC_E_WRONG_PRINCIPAL) av_log(h, AV_LOG_ERROR, "SNI or certificate check failed\n"); else av_log(h, AV_LOG_ERROR, "Creating security context failed (0x%lx)\n", sspi_ret); ret = AVERROR_UNKNOWN; goto fail; } if (inbuf[1].BufferType == SECBUFFER_EXTRA && inbuf[1].cbBuffer > 0) { if (c->enc_buf_offset > inbuf[1].cbBuffer) { memmove(c->enc_buf, (c->enc_buf + c->enc_buf_offset) - inbuf[1].cbBuffer, inbuf[1].cbBuffer); c->enc_buf_offset = inbuf[1].cbBuffer; if (sspi_ret == SEC_I_CONTINUE_NEEDED) { read_data = 0; continue; } } } else { c->enc_buf_offset = 0; } if (sspi_ret == SEC_I_CONTINUE_NEEDED) { read_data = 1; continue; } break; } return 0; fail: /* free any remaining output data */ for (i = 0; i < 3; i++) { if (outbuf[i].pvBuffer != NULL) { FreeContextBuffer(outbuf[i].pvBuffer); outbuf[i].pvBuffer = NULL; } } return ret; }
char* NtlmCreateResponseFromChallenge(HANDLE hSecurity, const char *szChallenge, const TCHAR* login, const TCHAR* psw, bool http, unsigned& complete) { if (hSecurity == NULL || ntlmCnt == 0) return NULL; SecBufferDesc outputBufferDescriptor, inputBufferDescriptor; SecBuffer outputSecurityToken, inputSecurityToken; TimeStamp tokenExpiration; ULONG contextAttributes; char *szOutputToken; NtlmHandleType* hNtlm = (NtlmHandleType*)hSecurity; if (mir_tstrcmpi(hNtlm->szProvider, _T("Basic"))) { bool isGSSAPI = mir_tstrcmpi(hNtlm->szProvider, _T("GSSAPI")) == 0; TCHAR *szProvider = isGSSAPI ? (TCHAR*)_T("Kerberos") : hNtlm->szProvider; bool hasChallenge = szChallenge != NULL && szChallenge[0] != '\0'; if (hasChallenge) { unsigned tokenLen; BYTE *token = (BYTE*)mir_base64_decode(szChallenge, &tokenLen); if (token == NULL) return NULL; if (isGSSAPI && complete) return CompleteGssapi(hSecurity, token, tokenLen); inputBufferDescriptor.cBuffers = 1; inputBufferDescriptor.pBuffers = &inputSecurityToken; inputBufferDescriptor.ulVersion = SECBUFFER_VERSION; inputSecurityToken.BufferType = SECBUFFER_TOKEN; inputSecurityToken.cbBuffer = tokenLen; inputSecurityToken.pvBuffer = token; // try to decode the domain name from the NTLM challenge if (login != NULL && login[0] != '\0' && !hNtlm->hasDomain) { NtlmType2packet* pkt = (NtlmType2packet*)token; if (!strncmp(pkt->sign, "NTLMSSP", 8) && pkt->type == 2) { wchar_t* domainName = (wchar_t*)&token[pkt->targetName.offset]; int domainLen = pkt->targetName.len; // Negotiate ANSI? if yes, convert the ANSI name to unicode if ((pkt->flags & 1) == 0) { int bufsz = MultiByteToWideChar(CP_ACP, 0, (char*)domainName, domainLen, NULL, 0); wchar_t* buf = (wchar_t*)alloca(bufsz * sizeof(wchar_t)); domainLen = MultiByteToWideChar(CP_ACP, 0, (char*)domainName, domainLen, buf, bufsz) - 1; domainName = buf; } else domainLen /= sizeof(wchar_t); if (domainLen) { size_t newLoginLen = mir_tstrlen(login) + domainLen + 1; TCHAR *newLogin = (TCHAR*)alloca(newLoginLen * sizeof(TCHAR)); _tcsncpy(newLogin, domainName, domainLen); newLogin[domainLen] = '\\'; mir_tstrcpy(newLogin + domainLen + 1, login); char* szChl = NtlmCreateResponseFromChallenge(hSecurity, NULL, newLogin, psw, http, complete); mir_free(szChl); } } } } else { if (SecIsValidHandle(&hNtlm->hClientContext)) DeleteSecurityContext(&hNtlm->hClientContext); if (SecIsValidHandle(&hNtlm->hClientCredential)) FreeCredentialsHandle(&hNtlm->hClientCredential); SEC_WINNT_AUTH_IDENTITY auth; if (login != NULL && login[0] != '\0') { memset(&auth, 0, sizeof(auth)); NetlibLogf(NULL, "Security login requested, user: %S pssw: %s", login, psw ? "(exist)" : "(no psw)"); const TCHAR* loginName = login; const TCHAR* domainName = _tcschr(login, '\\'); size_t domainLen = 0; size_t loginLen = mir_tstrlen(loginName); if (domainName != NULL) { loginName = domainName + 1; loginLen = mir_tstrlen(loginName); domainLen = domainName - login; domainName = login; } else if ((domainName = _tcschr(login, '@')) != NULL) { loginName = login; loginLen = domainName - login; domainLen = mir_tstrlen(++domainName); } auth.User = (PWORD)loginName; auth.UserLength = (ULONG)loginLen; auth.Password = (PWORD)psw; auth.PasswordLength = (ULONG)mir_tstrlen(psw); auth.Domain = (PWORD)domainName; auth.DomainLength = (ULONG)domainLen; auth.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE; hNtlm->hasDomain = domainLen != 0; } SECURITY_STATUS sc = AcquireCredentialsHandle(NULL, szProvider, SECPKG_CRED_OUTBOUND, NULL, hNtlm->hasDomain ? &auth : NULL, NULL, NULL, &hNtlm->hClientCredential, &tokenExpiration); if (sc != SEC_E_OK) { ReportSecError(sc, __LINE__); return NULL; } } outputBufferDescriptor.cBuffers = 1; outputBufferDescriptor.pBuffers = &outputSecurityToken; outputBufferDescriptor.ulVersion = SECBUFFER_VERSION; outputSecurityToken.BufferType = SECBUFFER_TOKEN; outputSecurityToken.cbBuffer = hNtlm->cbMaxToken; outputSecurityToken.pvBuffer = alloca(outputSecurityToken.cbBuffer); SECURITY_STATUS sc = InitializeSecurityContext(&hNtlm->hClientCredential, hasChallenge ? &hNtlm->hClientContext : NULL, hNtlm->szPrincipal, isGSSAPI ? ISC_REQ_MUTUAL_AUTH | ISC_REQ_STREAM : 0, 0, SECURITY_NATIVE_DREP, hasChallenge ? &inputBufferDescriptor : NULL, 0, &hNtlm->hClientContext, &outputBufferDescriptor, &contextAttributes, &tokenExpiration); complete = (sc != SEC_I_COMPLETE_AND_CONTINUE && sc != SEC_I_CONTINUE_NEEDED); if (sc == SEC_I_COMPLETE_NEEDED || sc == SEC_I_COMPLETE_AND_CONTINUE) sc = CompleteAuthToken(&hNtlm->hClientContext, &outputBufferDescriptor); if (sc != SEC_E_OK && sc != SEC_I_CONTINUE_NEEDED) { ReportSecError(sc, __LINE__); return NULL; } szOutputToken = mir_base64_encode((PBYTE)outputSecurityToken.pvBuffer, outputSecurityToken.cbBuffer); } else { if (!login || !psw) return NULL; char *szLogin = mir_t2a(login); char *szPassw = mir_t2a(psw); size_t authLen = mir_strlen(szLogin) + mir_strlen(szPassw) + 5; char *szAuth = (char*)alloca(authLen); int len = mir_snprintf(szAuth, authLen, "%s:%s", szLogin, szPassw); szOutputToken = mir_base64_encode((BYTE*)szAuth, len); complete = true; mir_free(szPassw); mir_free(szLogin); } if (szOutputToken == NULL) return NULL; if (!http) return szOutputToken; ptrA szProvider(mir_t2a(hNtlm->szProvider)); size_t resLen = mir_strlen(szOutputToken) + mir_strlen(szProvider) + 10; char *result = (char*)mir_alloc(resLen); mir_snprintf(result, resLen, "%s %s", szProvider, szOutputToken); mir_free(szOutputToken); return result; }
int sqAuthInitiate(char *method, char *username, char *password, char *domain, char *principal){ SEC_WINNT_AUTH_IDENTITY credentials; SECURITY_STATUS ret; ULONG flags = DEFAULT_AUTH_FLAGS; ULONG attrs = 0; sqAuthData *auth; if(debug) { printf("sqAuthInitiate: method=%s, user=%s, pass=%s, domain=%s\n", method, username, password, domain); } auth = calloc(1, sizeof(sqAuthData)); if(principal) auth->principal = strdup(principal); auth->sbdIn.ulVersion = SECBUFFER_VERSION; auth->sbdIn.pBuffers = auth->inbuf; auth->sbdOut.ulVersion = SECBUFFER_VERSION; auth->sbdOut.pBuffers = auth->outbuf; /* initialize additional credentials */ memset(&credentials,0,sizeof(SEC_WINNT_AUTH_IDENTITY)); // XXXX: fixme. use unicode and utf8 conversion credentials.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI; if(username) { credentials.User = username; credentials.UserLength = strlen(username); } if(password) { credentials.Password = password; credentials.PasswordLength = strlen(password); } if(domain) { credentials.Domain = domain; credentials.DomainLength = strlen(domain); } ret = AcquireCredentialsHandle(NULL, method, SECPKG_CRED_OUTBOUND, NULL, username ? &credentials : NULL, NULL, NULL, &auth->cred, &auth->expiry); if (ret != SEC_E_OK) { if(debug) printf("AquireCredentialsHandle error: %x\n", ret); return 0; } auth->outbuf[0].BufferType = SECBUFFER_TOKEN; auth->outbuf[0].cbBuffer = 0; auth->outbuf[0].pvBuffer = NULL; auth->outbuf[1].BufferType = SECBUFFER_EMPTY; auth->outbuf[1].cbBuffer = 0; auth->outbuf[1].pvBuffer = NULL; auth->sbdOut.cBuffers = 2; ret = InitializeSecurityContext(&auth->cred, NULL, auth->principal, flags, 0, SECURITY_NETWORK_DREP, NULL, 0, &auth->ctxt, &auth->sbdOut, &attrs, NULL); /* The only expected return value here is SEC_I_CONTINUE_NEEDED since we're just trying to establish the auth session */ if(ret != SEC_I_CONTINUE_NEEDED) { if(debug) printf("InitializeSecurityContext returned: %x\n", ret); return 0; } /* XXXX: fixme. return a real handle */ return (int)auth; }
OM_uint32 gss_init_sec_context (OM_uint32 *minor_status, gss_cred_id_t claimant_cred_handle, gss_ctx_id_t *context_handle, gss_name_t target_name,gss_OID mech_type, OM_uint32 req_flags,OM_uint32 time_req, gss_channel_bindings_t input_chan_bindings, gss_buffer_t input_token, gss_OID *actual_mech_type, gss_buffer_t output_token,OM_uint32 *ret_flags, OM_uint32 *time_rec) { OM_uint32 i; OM_uint32 major_status; TimeStamp expiry; SecBuffer ibuf[1],obuf[1]; SecBufferDesc ibufs,obufs; *minor_status = 0; /* never any minor status */ /* error if non-default time requested */ if (time_req) return GSS_S_FAILURE; if (mech_type && memcmp (mech_type,gss_mech_krb5,sizeof (gss_OID))) return GSS_S_BAD_MECH; /* ditto if any channel bindings */ if (input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS) return GSS_S_BAD_BINDINGS; /* apply default credential if necessary */ if (claimant_cred_handle == GSS_C_NO_CREDENTIAL) claimant_cred_handle = gss_default_cred; /* create output buffer storage as needed */ req_flags |= ISC_REQ_ALLOCATE_MEMORY; /* make output buffer */ obuf[0].BufferType = SECBUFFER_TOKEN; obuf[0].cbBuffer = 0; obuf[0].pvBuffer = NIL; /* output buffer descriptor */ obufs.ulVersion = SECBUFFER_VERSION; obufs.cBuffers = 1; obufs.pBuffers = obuf; /* first time caller? */ if (*context_handle == GSS_C_NO_CONTEXT) { /* yes, set up output context handle */ PCtxtHandle ctx = (PCtxtHandle) fs_get (sizeof (CtxtHandle)); major_status = InitializeSecurityContext (claimant_cred_handle,NIL, target_name,req_flags,0, SECURITY_NETWORK_DREP,NIL,0,ctx, &obufs, ret_flags ? ret_flags : &i, &expiry); *context_handle = ctx; /* return updated context */ } else { /* no, make SSPI buffer from GSSAPI buffer */ ibuf[0].BufferType = obuf[0].BufferType = SECBUFFER_TOKEN; ibuf[0].cbBuffer = input_token->length; ibuf[0].pvBuffer = input_token->value; /* input buffer descriptor */ ibufs.ulVersion = SECBUFFER_VERSION; ibufs.cBuffers = 1; ibufs.pBuffers = ibuf; major_status = InitializeSecurityContext (claimant_cred_handle, *context_handle,target_name, req_flags,0, SECURITY_NETWORK_DREP,&ibufs,0, *context_handle,&obufs, ret_flags ? ret_flags : &i, &expiry); } /* return output */ output_token->value = obuf[0].pvBuffer; output_token->length = obuf[0].cbBuffer; /* in case client wanted lifetime returned */ if (time_rec) *time_rec = expiry.LowPart; return major_status; }
static SSLSTREAM *ssl_start (TCPSTREAM *tstream,char *host,unsigned long flags) { SECURITY_STATUS e; ULONG a; TimeStamp t; SecBuffer ibuf[2],obuf[1]; SecBufferDesc ibufs,obufs; SCHANNEL_CRED tlscred; CERT_CONTEXT *cert; CERT_CHAIN_PARA chparam; CERT_CHAIN_CONTEXT *chain; SSL_EXTRA_CERT_CHAIN_POLICY_PARA policy; CERT_CHAIN_POLICY_PARA polparam; CERT_CHAIN_POLICY_STATUS status; char tmp[MAILTMPLEN],certname[256]; char *reason = NIL; ULONG req = ISC_REQ_REPLAY_DETECT | ISC_REQ_SEQUENCE_DETECT | ISC_REQ_CONFIDENTIALITY | ISC_REQ_USE_SESSION_KEY | ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM | ISC_REQ_EXTENDED_ERROR | ISC_REQ_MANUAL_CRED_VALIDATION; LPSTR usage[] = { szOID_PKIX_KP_SERVER_AUTH, szOID_SERVER_GATED_CRYPTO, szOID_SGC_NETSCAPE }; PWSTR whost = NIL; char *buf = (char *) fs_get (ssltsz); unsigned long size = 0; sslcertificatequery_t scq = (sslcertificatequery_t) mail_parameters (NIL,GET_SSLCERTIFICATEQUERY,NIL); sslfailure_t sf = (sslfailure_t) mail_parameters (NIL,GET_SSLFAILURE,NIL); SSLSTREAM *stream = (SSLSTREAM *) memset (fs_get (sizeof (SSLSTREAM)),0, sizeof (SSLSTREAM)); stream->tcpstream = tstream; /* bind TCP stream */ /* initialize TLS credential */ memset (&tlscred,0,sizeof (SCHANNEL_CRED)); tlscred.dwVersion = SCHANNEL_CRED_VERSION; tlscred.grbitEnabledProtocols = SP_PROT_TLS1; /* acquire credentials */ if (AcquireCredentialsHandle (NIL,UNISP_NAME,SECPKG_CRED_OUTBOUND,NIL,(flags & NET_TLSCLIENT) ? &tlscred : NIL,NIL,NIL,&stream->cred,&t) != SEC_E_OK) reason = "Acquire credentials handle failed"; else while (!reason) { /* negotiate security context */ /* initialize buffers */ ibuf[0].cbBuffer = size; ibuf[0].pvBuffer = buf; ibuf[1].cbBuffer = 0; ibuf[1].pvBuffer = NIL; obuf[0].cbBuffer = 0; obuf[0].pvBuffer = NIL; ibuf[0].BufferType = obuf[0].BufferType = SECBUFFER_TOKEN; ibuf[1].BufferType = SECBUFFER_EMPTY; /* initialize buffer descriptors */ ibufs.ulVersion = obufs.ulVersion = SECBUFFER_VERSION; ibufs.cBuffers = 2; obufs.cBuffers = 1; ibufs.pBuffers = ibuf; obufs.pBuffers = obuf; /* negotiate security */ e = InitializeSecurityContext (&stream->cred,size ? &stream->context : NIL,host,req,0, SECURITY_NETWORK_DREP,size? &ibufs:NIL,0,&stream->context,&obufs,&a,&t); /* have an output buffer we need to send? */ if (obuf[0].pvBuffer && obuf[0].cbBuffer) { if (!tcp_sout (stream->tcpstream,obuf[0].pvBuffer,obuf[0].cbBuffer)) reason = "Unexpected TCP output disconnect"; /* free the buffer */ FreeContextBuffer (obuf[0].pvBuffer); } if (!reason) switch (e) { /* negotiation state */ case SEC_I_INCOMPLETE_CREDENTIALS: break; /* server wants client auth */ case SEC_I_CONTINUE_NEEDED: if (size) { /* continue, read any data? */ /* yes, anything regurgiated back to us? */ if (ibuf[1].BufferType == SECBUFFER_EXTRA) { /* yes, set this as the new data */ memmove (buf,buf + size - ibuf[1].cbBuffer,ibuf[1].cbBuffer); size = ibuf[1].cbBuffer; break; } size = 0; /* otherwise, read more stuff from server */ } case SEC_E_INCOMPLETE_MESSAGE: /* need to read more data from server */ if (!tcp_getdata (stream->tcpstream)) reason = "Unexpected TCP input disconnect"; else { memcpy (buf+size,stream->tcpstream->iptr,stream->tcpstream->ictr); size += stream->tcpstream->ictr; /* empty it from TCP's buffers */ stream->tcpstream->iptr += stream->tcpstream->ictr; stream->tcpstream->ictr = 0; } break; case SEC_E_OK: /* success, any data to be regurgitated? */ if (ibuf[1].BufferType == SECBUFFER_EXTRA) { /* yes, set this as the new data */ memmove (stream->tcpstream->iptr = stream->tcpstream->ibuf, buf + size - ibuf[1].cbBuffer,ibuf[1].cbBuffer); stream->tcpstream->ictr = ibuf[1].cbBuffer; } if (!(flags & NET_NOVALIDATECERT)) { /* need validation, make wchar of host */ if (!((size = MultiByteToWideChar (CP_ACP,0,host,-1,NIL,0)) && (whost = (PWSTR) fs_get (size*sizeof (WCHAR))) && MultiByteToWideChar (CP_ACP,0,host,-1,whost,size))) fatal ("Can't make wchar of host name!"); /* get certificate */ if ((QueryContextAttributes (&stream->context,SECPKG_ATTR_REMOTE_CERT_CONTEXT,&cert) != SEC_E_OK) || !cert) { reason = "*Unable to get certificate"; strcpy (certname,"<no certificate>"); } else { /* get certificate subject name */ CertNameToStr (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, &cert->pCertInfo->Subject,CERT_X500_NAME_STR, certname,255); /* build certificate chain */ memset (&chparam,0,sizeof (chparam)); chparam.cbSize = sizeof (chparam); chparam.RequestedUsage.dwType = USAGE_MATCH_TYPE_OR; chparam.RequestedUsage.Usage.rgpszUsageIdentifier = usage; chparam.RequestedUsage.Usage.cUsageIdentifier = sizeof (usage) / sizeof (LPSTR); if (!CertGetCertificateChain (NIL,cert,NIL,cert->hCertStore,&chparam,NIL,NIL,&chain)) reason = ssl_analyze_status (GetLastError (),tmp); else { /* validate certificate chain */ memset (&policy,0,sizeof (SSL_EXTRA_CERT_CHAIN_POLICY_PARA)); policy.cbStruct = sizeof (SSL_EXTRA_CERT_CHAIN_POLICY_PARA); policy.dwAuthType = AUTHTYPE_SERVER; policy.fdwChecks = NIL; policy.pwszServerName = whost; memset (&polparam,0,sizeof (polparam)); polparam.cbSize = sizeof (polparam); polparam.pvExtraPolicyPara = &policy; memset (&status,0,sizeof (status)); status.cbSize = sizeof (status); if (!CertVerifyCertificateChainPolicy (CERT_CHAIN_POLICY_SSL,chain,&polparam,&status)) reason = ssl_analyze_status (GetLastError (),tmp); else if (status.dwError) reason = ssl_analyze_status (status.dwError,tmp); CertFreeCertificateChain (chain); } } if (whost) fs_give ((void **) &whost); if (reason) { /* got an error? */ /* application callback */ if (scq) reason = (*scq) ((*reason == '*') ? reason + 1 : reason, host,certname) ? NIL : ""; else if (*certname) { /* error message to return via mm_log() */ sprintf (buf,"*%.128s: %.255s", (*reason == '*') ? reason + 1 : reason,certname); reason = buf; } } } if (reason || (reason = ssl_analyze_status (QueryContextAttributes (&stream->context,SECPKG_ATTR_STREAM_SIZES,&stream->sizes),buf))) break; /* error in certificate or getting sizes */ fs_give ((void **) &buf); /* flush temporary buffer */ /* make maximum-sized buffers */ stream->bufsize = stream->sizes.cbHeader + stream->sizes.cbMaximumMessage + stream->sizes.cbTrailer; if (stream->sizes.cbMaximumMessage < SSLBUFLEN) fatal ("cbMaximumMessage is less than SSLBUFLEN!"); else if (stream->sizes.cbMaximumMessage < 16384) { sprintf (tmp,"WINDOWS BUG: cbMaximumMessage = %ld, should be 16384", (long) stream->sizes.cbMaximumMessage); mm_log (tmp,NIL); } stream->ibuf = (char *) fs_get (stream->bufsize); stream->obuf = (char *) fs_get (stream->bufsize); return stream; default: reason = ssl_analyze_status (e,buf); } } ssl_close (stream); /* failed to do SSL */ stream = NIL; /* no stream returned */ switch (*reason) { /* analyze reason */ case '*': /* certificate failure */ ++reason; /* skip over certificate failure indication */ /* pass to error callback */ if (sf) (*sf) (host,reason,flags); else { /* no error callback, build error message */ sprintf (tmp,"Certificate failure for %.80s: %.512s",host,reason); mm_log (tmp,ERROR); } case '\0': /* user answered no to certificate callback */ if (flags & NET_TRYSSL) /* return dummy stream to stop tryssl */ stream = (SSLSTREAM *) memset (fs_get (sizeof (SSLSTREAM)),0, sizeof (SSLSTREAM)); break; default: /* non-certificate failure */ if (flags & NET_TRYSSL); /* no error output if tryssl */ /* pass to error callback */ else if (sf) (*sf) (host,reason,flags); else { /* no error callback, build error message */ sprintf (tmp,"TLS/SSL failure for %.80s: %.512s",host,reason); mm_log (tmp,ERROR); } break; } fs_give ((void **) &buf); /* flush temporary buffer */ return stream; }
void SchannelContext::connect() { ScopedCertContext pCertContext; m_state = Connecting; // If a user name is specified, then attempt to find a client // certificate. Otherwise, just create a NULL credential. if (!m_cert_name.empty()) { if (m_my_cert_store == NULL) { m_my_cert_store = CertOpenSystemStore(0, m_cert_store_name.c_str()); if (!m_my_cert_store) { ///// printf( "**** Error 0x%x returned by CertOpenSystemStore\n", GetLastError() ); indicateError(); return; } } pCertContext = findCertificateInStore( m_my_cert_store, m_cert_name ); if (pCertContext == NULL) { ///// printf("**** Error 0x%x returned by CertFindCertificateInStore\n", GetLastError()); indicateError(); return; } } // We use an empty list for client certificates PCCERT_CONTEXT clientCerts[1] = {0}; SCHANNEL_CRED sc = {0}; sc.dwVersion = SCHANNEL_CRED_VERSION; /////SSL3? sc.grbitEnabledProtocols = SP_PROT_SSL3_CLIENT | SP_PROT_TLS1_CLIENT | SP_PROT_TLS1_1_CLIENT | SP_PROT_TLS1_2_CLIENT; sc.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION; if (pCertContext) { sc.cCreds = 1; sc.paCred = pCertContext.GetPointer(); sc.dwFlags |= SCH_CRED_NO_DEFAULT_CREDS; } else { sc.cCreds = 0; // Let Crypto API find the appropriate certificate for us sc.paCred = clientCerts; sc.dwFlags |= SCH_CRED_USE_DEFAULT_CREDS; } // Swiften performs the server name check for us sc.dwFlags |= SCH_CRED_NO_SERVERNAME_CHECK; SECURITY_STATUS status = AcquireCredentialsHandle( NULL, UNISP_NAME, SECPKG_CRED_OUTBOUND, NULL, &sc, NULL, NULL, m_credHandle.Reset(), NULL); if (status != SEC_E_OK) { // We failed to obtain the credentials handle indicateError(); return; } SecBuffer outBuffers[2]; // We let Schannel allocate the output buffer for us outBuffers[0].pvBuffer = NULL; outBuffers[0].cbBuffer = 0; outBuffers[0].BufferType = SECBUFFER_TOKEN; // Contains alert data if an alert is generated outBuffers[1].pvBuffer = NULL; outBuffers[1].cbBuffer = 0; outBuffers[1].BufferType = SECBUFFER_ALERT; // Make sure the output buffers are freed ScopedSecBuffer scopedOutputData(&outBuffers[0]); ScopedSecBuffer scopedOutputAlertData(&outBuffers[1]); SecBufferDesc outBufferDesc = {0}; outBufferDesc.cBuffers = 2; outBufferDesc.pBuffers = outBuffers; outBufferDesc.ulVersion = SECBUFFER_VERSION; // Create the initial security context status = InitializeSecurityContext( m_credHandle, NULL, NULL, m_ctxtFlags, 0, 0, NULL, 0, m_ctxtHandle.Reset(), &outBufferDesc, &m_secContext, NULL); if (status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) { // We failed to initialize the security context handleCertError(status); indicateError(); return; } // Start the handshake sendDataOnNetwork(outBuffers[0].pvBuffer, outBuffers[0].cbBuffer); if (status == SEC_E_OK) { status = validateServerCertificate(); if (status != SEC_E_OK) handleCertError(status); m_state = Connected; determineStreamSizes(); onConnected(); } }
static void on_underlying_io_open_complete(void* context, IO_OPEN_RESULT io_open_result) { TLS_IO_INSTANCE* tls_io_instance = (TLS_IO_INSTANCE*)context; if (tls_io_instance->tlsio_state != TLSIO_STATE_OPENING_UNDERLYING_IO) { tls_io_instance->tlsio_state = TLSIO_STATE_ERROR; indicate_error(tls_io_instance); } else { SecBuffer init_security_buffers[2]; ULONG context_attributes; SECURITY_STATUS status; SCHANNEL_CRED auth_data; auth_data.dwVersion = SCHANNEL_CRED_VERSION; auth_data.cCreds = 0; auth_data.paCred = NULL; auth_data.hRootStore = NULL; auth_data.cSupportedAlgs = 0; auth_data.palgSupportedAlgs = NULL; auth_data.grbitEnabledProtocols = 0; auth_data.dwMinimumCipherStrength = 0; auth_data.dwMaximumCipherStrength = 0; auth_data.dwSessionLifespan = 0; auth_data.dwFlags = SCH_USE_STRONG_CRYPTO | SCH_CRED_NO_DEFAULT_CREDS; auth_data.dwCredFormat = 0; status = AcquireCredentialsHandle(NULL, UNISP_NAME, SECPKG_CRED_OUTBOUND, NULL, &auth_data, NULL, NULL, &tls_io_instance->credential_handle, NULL); if (status != SEC_E_OK) { tls_io_instance->tlsio_state = TLSIO_STATE_ERROR; indicate_error(tls_io_instance); } else { tls_io_instance->credential_handle_allocated = true; init_security_buffers[0].cbBuffer = 0; init_security_buffers[0].BufferType = SECBUFFER_TOKEN; init_security_buffers[0].pvBuffer = NULL; init_security_buffers[1].cbBuffer = 0; init_security_buffers[1].BufferType = SECBUFFER_EMPTY; init_security_buffers[1].pvBuffer = 0; SecBufferDesc security_buffers_desc; security_buffers_desc.cBuffers = 2; security_buffers_desc.pBuffers = init_security_buffers; security_buffers_desc.ulVersion = SECBUFFER_VERSION; status = InitializeSecurityContext(&tls_io_instance->credential_handle, NULL, (SEC_CHAR*)tls_io_instance->host_name, ISC_REQ_EXTENDED_ERROR | ISC_REQ_STREAM | ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_USE_SUPPLIED_CREDS, 0, 0, NULL, 0, &tls_io_instance->security_context, &security_buffers_desc, &context_attributes, NULL); if ((status == SEC_I_COMPLETE_NEEDED) || (status == SEC_I_CONTINUE_NEEDED) || (status == SEC_I_COMPLETE_AND_CONTINUE)) { if (xio_send(tls_io_instance->socket_io, init_security_buffers[0].pvBuffer, init_security_buffers[0].cbBuffer, NULL, NULL) != 0) { tls_io_instance->tlsio_state = TLSIO_STATE_ERROR; indicate_error(tls_io_instance); } else { /* set the needed bytes to 1, to get on the next byte how many we actually need */ tls_io_instance->needed_bytes = 1; if (resize_receive_buffer(tls_io_instance, tls_io_instance->needed_bytes + tls_io_instance->received_byte_count) != 0) { tls_io_instance->tlsio_state = TLSIO_STATE_ERROR; indicate_error(tls_io_instance); } else { tls_io_instance->tlsio_state = TLSIO_STATE_HANDSHAKE_CLIENT_HELLO_SENT; } } } } } }
SECURITY_STATUS getToken(char **negotiateToken, WCHAR *targetName, WCHAR *hostName) { //---------------------------------------------------------------------- unsigned long cPackages; PSecPkgInfo PackageInfo; SECURITY_STATUS stat; // Get the name of the package stat = EnumerateSecurityPackages( &cPackages, &PackageInfo); if (stat != SEC_E_OK) { wprintf( L"Security function failed with error: %i\n", stat); return stat; } SEC_WCHAR *szPackage = PackageInfo->Name; unsigned long m_cbMaxToken = PackageInfo->cbMaxToken; PBYTE m_pOutBuf = (PBYTE)malloc(m_cbMaxToken); //-------------------------------------------------------------------- CredHandle hCredential; TimeStamp tsExpiry; PSEC_WINNT_AUTH_IDENTITY_OPAQUE pAuthIdentity = NULL; // The structure for storing user data entered stat = AcquireCredentialsHandle( NULL, szPackage, SECPKG_CRED_OUTBOUND, NULL, pAuthIdentity, NULL, NULL, &hCredential, &tsExpiry); if (stat != SEC_E_OK) { wprintf( L"Credentials function failed with error: %i\n", stat); return stat; } //-------------------------------------------------------------------- CtxtHandle m_hCtxt; SecBufferDesc outSecBufDesc; SecBuffer outSecBuf; unsigned long fContextAttr; // prepare output buffer outSecBufDesc.ulVersion = 0; outSecBufDesc.cBuffers = 1; outSecBufDesc.pBuffers = &outSecBuf; outSecBuf.cbBuffer = m_cbMaxToken; outSecBuf.BufferType = SECBUFFER_TOKEN; outSecBuf.pvBuffer = m_pOutBuf; stat = InitializeSecurityContext( &hCredential, NULL, targetName, ISC_REQ_CONFIDENTIALITY, 0, // reserved1 SECURITY_NATIVE_DREP, NULL, 0, // reserved2 &m_hCtxt, &outSecBufDesc, &fContextAttr, &tsExpiry); FreeCredentialsHandle(&hCredential); switch (stat) { case SEC_I_CONTINUE_NEEDED: case SEC_I_COMPLETE_AND_CONTINUE: CompleteAuthToken(&m_hCtxt, &outSecBufDesc); break; case SEC_E_OK: break; default: return stat; } DeleteSecurityContext(&m_hCtxt); FreeContextBuffer(PackageInfo); if (outSecBuf.cbBuffer) { base64_encode(reinterpret_cast < char* > (m_pOutBuf), outSecBuf.cbBuffer, negotiateToken); } else { return -1; } if (strlen(*negotiateToken) < 500) { CREDUI_INFO creduiInfo = { 0 }; creduiInfo.cbSize = sizeof(creduiInfo); // Change the message text and caption to the actual text for your dialog. SEC_WCHAR message[NI_MAXHOST]; _snwprintf_s( message, NI_MAXHOST, _TRUNCATE, L"Enter your username and password to connect to %s", hostName); creduiInfo.pszCaptionText = L"Connect to the proxy-server"; creduiInfo.pszMessageText = message; BOOL fSave = TRUE; // Checkmark "Remember user" stat = SspiPromptForCredentials( targetName, &creduiInfo, 0, szPackage, NULL, &pAuthIdentity, &fSave, 0); } return SEC_E_OK; }
/* * Continue SSPI authentication with next token as needed. */ static int pg_SSPI_continue(PGconn *conn) { SECURITY_STATUS r; CtxtHandle newContext; ULONG contextAttr; SecBufferDesc inbuf; SecBufferDesc outbuf; SecBuffer OutBuffers[1]; SecBuffer InBuffers[1]; if (conn->sspictx != NULL) { /* * On runs other than the first we have some data to send. Put this * data in a SecBuffer type structure. */ inbuf.ulVersion = SECBUFFER_VERSION; inbuf.cBuffers = 1; inbuf.pBuffers = InBuffers; InBuffers[0].pvBuffer = conn->ginbuf.value; InBuffers[0].cbBuffer = conn->ginbuf.length; InBuffers[0].BufferType = SECBUFFER_TOKEN; } OutBuffers[0].pvBuffer = NULL; OutBuffers[0].BufferType = SECBUFFER_TOKEN; OutBuffers[0].cbBuffer = 0; outbuf.cBuffers = 1; outbuf.pBuffers = OutBuffers; outbuf.ulVersion = SECBUFFER_VERSION; r = InitializeSecurityContext(conn->sspicred, conn->sspictx, conn->sspitarget, ISC_REQ_ALLOCATE_MEMORY, 0, SECURITY_NETWORK_DREP, (conn->sspictx == NULL) ? NULL : &inbuf, 0, &newContext, &outbuf, &contextAttr, NULL); if (r != SEC_E_OK && r != SEC_I_CONTINUE_NEEDED) { pg_SSPI_error(conn, libpq_gettext("SSPI continuation error"), r); return STATUS_ERROR; } if (conn->sspictx == NULL) { /* On first run, transfer retreived context handle */ conn->sspictx = malloc(sizeof(CtxtHandle)); if (conn->sspictx == NULL) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("out of memory\n")); return STATUS_ERROR; } memcpy(conn->sspictx, &newContext, sizeof(CtxtHandle)); } else { /* * On subsequent runs when we had data to send, free buffers that * contained this data. */ free(conn->ginbuf.value); conn->ginbuf.value = NULL; conn->ginbuf.length = 0; } /* * If SSPI returned any data to be sent to the server (as it normally * would), send this data as a password packet. */ if (outbuf.cBuffers > 0) { if (outbuf.cBuffers != 1) { /* * This should never happen, at least not for Kerberos * authentication. Keep check in case it shows up with other * authentication methods later. */ printfPQExpBuffer(&conn->errorMessage, "SSPI returned invalid number of output buffers\n"); return STATUS_ERROR; } /* * If the negotiation is complete, there may be zero bytes to send. * The server is at this point not expecting any more data, so don't * send it. */ if (outbuf.pBuffers[0].cbBuffer > 0) { if (pqPacketSend(conn, 'p', outbuf.pBuffers[0].pvBuffer, outbuf.pBuffers[0].cbBuffer)) { FreeContextBuffer(outbuf.pBuffers[0].pvBuffer); return STATUS_ERROR; } } FreeContextBuffer(outbuf.pBuffers[0].pvBuffer); } /* Cleanup is handled by the code in freePGconn() */ return STATUS_OK; }
static SECURITY_STATUS PerformSchannelClientHandshake( SOCKET Socket, /* in */ PCredHandle phCreds, /* in */ LPSTR pszServerName, /* in */ CtxtHandle *phContext, /* out */ SecBuffer *pExtraData) /* out */ { SecBufferDesc OutBuffer; SecBuffer OutBuffers[1]; DWORD dwSSPIFlags; DWORD dwSSPIOutFlags; TimeStamp tsExpiry; SECURITY_STATUS scRet; DWORD cbData; dwSSPIFlags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT | ISC_REQ_CONFIDENTIALITY | ISC_RET_EXTENDED_ERROR | ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM; /* * Initiate a ClientHello message and generate a token. */ OutBuffers[0].pvBuffer = NULL; OutBuffers[0].BufferType = SECBUFFER_TOKEN; OutBuffers[0].cbBuffer = 0; OutBuffer.cBuffers = 1; OutBuffer.pBuffers = OutBuffers; OutBuffer.ulVersion = SECBUFFER_VERSION; scRet = InitializeSecurityContext( phCreds, NULL, pszServerName, dwSSPIFlags, 0, SECURITY_NATIVE_DREP, NULL, 0, phContext, &OutBuffer, &dwSSPIOutFlags, &tsExpiry); if (scRet != SEC_I_CONTINUE_NEEDED) { mylog("**** Error %d returned by InitializeSecurityContext (1)\n", scRet); return scRet; } /* Send response to server if there is one. */ if (OutBuffers[0].cbBuffer != 0 && OutBuffers[0].pvBuffer != NULL) { cbData = sendall(Socket, OutBuffers[0].pvBuffer, OutBuffers[0].cbBuffer); if (cbData <= 0) { mylog("**** Error %d sending data to server (1)\n", SOCK_ERRNO); FreeContextBuffer(OutBuffers[0].pvBuffer); DeleteSecurityContext(phContext); return SEC_E_INTERNAL_ERROR; } mylog("%d bytes of handshake data sent\n", cbData); /* Free output buffer. */ FreeContextBuffer(OutBuffers[0].pvBuffer); OutBuffers[0].pvBuffer = NULL; } return SchannelClientHandshakeLoop(Socket, phCreds, phContext, TRUE, pExtraData); }