Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2075 lines
52 KiB

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1995.
//
// File: context.c
//
// Contents:
//
// Classes:
//
// Functions:
//
// History: 8-08-95 RichardW Created
//
//----------------------------------------------------------------------------
#include "sslsspi.h"
#define VALID_REQUEST_FLAGS ( ISC_REQ_MUTUAL_AUTH | \
ISC_REQ_REPLAY_DETECT | \
ISC_REQ_SEQUENCE_DETECT | \
ISC_REQ_CONFIDENTIALITY | \
ISC_REQ_ALLOCATE_MEMORY | \
ISC_REQ_STREAM )
#include "md5.h"
#ifdef SSL_DOMESTIC
CSystems ValidSystems[] = { { 0x00010080, 0, 16, 128 },
{ 0x00020080, 11, 5, 128 },
} ;
#else
CSystems ValidSystems[] = { { 0x00020080, 11, 5, 128} };
#endif
PSslContext ServerSaveArray[256];
PSslContext SslLRU;
CRITICAL_SECTION SessionCritSec;
DWORD SslKeepAliveTime = 100 * 1000;
#if defined(TIMERS)
#define ENABLE_TIMERS 1
NTSYSAPI
long
NTAPI
NtQueryPerformanceCounter (
OUT PLARGE_INTEGER PerformanceCounter,
OUT PLARGE_INTEGER PerformanceFrequency OPTIONAL
);
#else
#define ENABLE_TIMERS 0
#endif
#if DBG
typedef struct _DbgMapCrypto {
DWORD C;
PSTR psz;
} DbgMapCrypto;
DbgMapCrypto DbgCryptoNames[] = { {CRYPTO_RC4_128, "RC4 128"},
{CRYPTO_RC4_40, "RC4 128 - 40"},
{CRYPTO_RC2_128, "RC2 128"},
{CRYPTO_RC2_40, "RC2 128 - 40"},
{CRYPTO_IDEA_128, "IDEA 128"},
{CRYPTO_NULL, "Null"},
{CRYPTO_DES_64, "DES 64"},
{CRYPTO_3DES_192, "3DES 192"}
};
PSTR DbgAlgNames[] = { "Basic RSA", "RSA with MD2", "RSA with MD5", "RC4 stream"};
#define AlgName(x) ((x < sizeof(DbgAlgNames) / sizeof(PSTR)) ? DbgAlgNames[x] : "Unknown")
PSTR
DbgGetNameOfCrypto(DWORD x)
{
int i;
for (i = 0; i < sizeof(DbgCryptoNames) / sizeof(DbgMapCrypto) ; i++ )
{
if (x == DbgCryptoNames[i].C)
{
return(DbgCryptoNames[i].psz);
}
}
return("Unknown");
}
#endif
//
// These next few functions handle the "dead" session list. SSL provides
// for storing sessions for up to n (usually 100) seconds after they are
// closed, since the HTTP protocol is designed to do quite a few opens and
// closes.
//
BOOL
SslInitializeSessions( VOID )
{
ZeroMemory( ServerSaveArray, sizeof( ServerSaveArray ) );
InitializeCriticalSection( &SessionCritSec );
return( TRUE );
}
VOID
SslUnlinkContext( PSslContext pContext )
{
if (pContext->pPrev)
{
pContext->pPrev->pNext = pContext->pNext;
}
if (pContext->pNext)
{
pContext->pNext->pPrev = pContext->pPrev;
}
pContext->pNext = NULL;
pContext->pPrev = NULL;
if (pContext->pHashPrev)
{
pContext->pHashPrev->pNext = pContext->pHashNext;
}
else
{
ServerSaveArray[pContext->ServerSessionId.bSessionId[0]] = pContext->pHashNext;
}
if (pContext->pHashNext)
{
pContext->pHashNext->pHashPrev = pContext->pHashPrev;
}
pContext->pHashNext = NULL;
pContext->pHashPrev = NULL;
}
VOID
SslPurgeOldEntries( VOID )
{
PSslContext pContext;
PSslContext pNext;
DWORD Now;
Now = GetTickCount();
pContext = SslLRU;
while (pContext && (pContext->ExpiryTime < Now) )
{
pNext = pContext->pNext;
SslUnlinkContext( pContext );
SslDeleteContext( pContext );
DebugLog((DEB_TRACE_CACHE, "Deleted expired entry\n"));
pContext = pNext;
}
SslLRU = pContext;
}
BOOL
SslCacheSession(PSslContext pContext )
{
DWORD index;
pContext->ExpiryTime = GetTickCount() + SslKeepAliveTime;
DebugLog((DEB_TRACE_CACHE, "Saving session for %d seconds\n",
SslKeepAliveTime / 1000));
EnterCriticalSection( &SessionCritSec );
SslPurgeOldEntries();
if (SslLRU)
{
SslLRU->pPrev = pContext;
}
pContext->pNext = SslLRU;
SslLRU = pContext;
index = pContext->ServerSessionId.bSessionId[0];
if (ServerSaveArray[index])
{
ServerSaveArray[index]->pHashPrev = pContext;
}
pContext->pHashNext = ServerSaveArray[index];
ServerSaveArray[index] = pContext;
LeaveCriticalSection( &SessionCritSec );
return( TRUE );
}
PSslContext
SslFindSession(PSslSessionId pId)
{
DWORD index;
PSslContext pContext;
index = pId->bSessionId[0];
EnterCriticalSection( &SessionCritSec );
SslPurgeOldEntries();
pContext = ServerSaveArray[index];
while (pContext)
{
if (memcmp(pContext->ServerSessionId.bSessionId,
pId->bSessionId,
pId->cbSessionId) == 0)
{
break;
}
pContext = pContext->pHashNext;
}
if (pContext)
{
SslUnlinkContext( pContext );
}
LeaveCriticalSection( &SessionCritSec );
return( pContext );
}
//+---------------------------------------------------------------------------
//
// Function: MakeSessionKeys
//
// Synopsis: Makes the session keys for the context...
//
// Arguments: [pContext] --
// [Bits] --
//
// Algorithm:
//
// History: 10-10-95 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
BOOL
MakeSessionKeys(
PSslContext pContext,
DWORD Bits)
{
MD5_CTX KeyMaterial0;
MD5_CTX KeyMaterial1;
UCHAR Buffer[MASTER_KEY_SIZE + 1 +
SSL_MAX_CHALLENGE_LEN + SSL_MAX_CONNECTION_ID_LEN];
DWORD BufferLen;
if (Bits != 128)
{
return( FALSE );
}
CopyMemory(Buffer, pContext->MasterKey, 16 );
BufferLen = 16;
Buffer[BufferLen++] = '0';
CopyMemory(&Buffer[17], pContext->Challenge, pContext->ChallengeLength );
BufferLen += pContext->ChallengeLength ;
CopyMemory( &Buffer[BufferLen],
pContext->ServerSessionId.bSessionId,
pContext->ServerSessionId.cbSessionId );
BufferLen += pContext->ServerSessionId.cbSessionId ;
MD5Init( &KeyMaterial0 );
MD5Update( &KeyMaterial0, Buffer, BufferLen );
MD5Final( &KeyMaterial0 );
Buffer[16] = '1';
MD5Init( &KeyMaterial1 );
MD5Update( &KeyMaterial1, Buffer, BufferLen );
MD5Final( &KeyMaterial1 );
pContext->KeySize = 16;
if (pContext->Flags & CONTEXT_FLAG_OUTBOUND)
{
CopyMemory(pContext->ReadKey, KeyMaterial0.digest, CONTEXT_KEY_SIZE);
CopyMemory(pContext->WriteKey, KeyMaterial1.digest, CONTEXT_KEY_SIZE);
}
else
{
CopyMemory(pContext->ReadKey, KeyMaterial1.digest, CONTEXT_KEY_SIZE);
CopyMemory(pContext->WriteKey, KeyMaterial0.digest, CONTEXT_KEY_SIZE);
}
if (pContext->pSystem->Initialize( pContext->ReadKey,
CONTEXT_KEY_SIZE,
&pContext->pReadState ) )
{
if (pContext->pSystem->Initialize( pContext->WriteKey,
CONTEXT_KEY_SIZE,
&pContext->pWriteState) )
{
if (pContext->pCheck->Initialize( 0, &pContext->pReadBuffer))
{
pContext->pCheck->Sum( pContext->pReadBuffer,
pContext->KeySize,
pContext->ReadKey);
if (pContext->pCheck->Initialize( 0, &pContext->pWriteBuffer))
{
pContext->pCheck->Sum( pContext->pWriteBuffer,
pContext->KeySize,
pContext->WriteKey );
return( TRUE );
}
pContext->pCheck->Finish( &pContext->pReadBuffer );
}
pContext->pSystem->Discard( &pContext->pWriteState );
}
pContext->pSystem->Discard( &pContext->pReadState );
}
return( FALSE );
}
PSTR
CopyString(
PSTR pszString)
{
PSTR pszNewString;
DWORD cchString;
cchString = strlen(pszString) + 1;
pszNewString = SslAlloc('ypoC', LMEM_FIXED, cchString);
if (pszNewString)
{
CopyMemory(pszNewString, pszString, cchString);
}
return(pszNewString);
}
PSslContext
SslCreateContext(
VOID)
{
PSslContext pContext;
pContext = SslAlloc('txtC', LMEM_FIXED | LMEM_ZEROINIT, sizeof(SslContext));
if (pContext)
{
pContext->Magic = SSL_CONTEXT_MAGIC;
}
return(pContext);
}
VOID
SslDeleteContext(
PSslContext pContext)
{
if (pContext->pszName)
{
SslFree(pContext->pszName);
}
if ( pContext->pCred )
{
SslDereferenceCredential( pContext->pCred );
}
if ( pContext->pSystem )
{
if ( pContext->pReadState )
{
pContext->pSystem->Discard( &pContext->pReadState );
}
if ( pContext->pWriteState )
{
pContext->pSystem->Discard( &pContext->pWriteState );
}
}
if ( pContext->pCheck )
{
if ( pContext->pReadBuffer )
{
pContext->pCheck->Finish( &pContext->pReadBuffer );
}
if ( pContext->pWriteBuffer )
{
pContext->pCheck->Finish( &pContext->pWriteBuffer );
}
}
if ( pContext->pCertificate )
{
SslFree( pContext->pCertificate );
}
ZeroMemory( pContext, sizeof( SslContext ) );
SslFree( pContext );
}
PSslContext
SslpValidateContextHandle(
PCtxtHandle phContext)
{
PSslContext pContext = NULL;
BOOL fReturn;
fReturn = FALSE;
if (phContext)
{
try
{
pContext = (PSslContext) phContext->dwUpper;
if (pContext->Magic == SSL_CONTEXT_MAGIC)
{
fReturn = TRUE;
}
}
except (EXCEPTION_EXECUTE_HANDLER)
{
pContext = NULL;
}
}
if (fReturn)
{
return(pContext);
}
return(NULL);
}
SECURITY_STATUS
SslHandleServerHello(
PSslContext pContext,
PSecBufferDesc pInput,
PCtxtHandle phNewContext,
PSecBufferDesc pOutput,
unsigned long SEC_FAR * pfContextAttr,
PTimeStamp ptsExpiry
)
{
SECURITY_STATUS scRet;
PServer_Hello pHello;
Client_Master_Key Key;
DWORD i;
BOOL fPack;
PSecBuffer pBuffer;
PX509Certificate pCertificate;
PUCHAR pPortionToEncrypt;
DWORD BytesToEncrypt;
UCHAR Temp[16];
if (!pOutput)
{
return(SEC_E_INVALID_TOKEN);
}
if (pOutput->cBuffers < 1)
{
return(SEC_E_INVALID_TOKEN);
}
if (!UnpackServerHello(TRUE,
(PSsl_Server_Hello) pInput->pBuffers[0].pvBuffer,
pInput->pBuffers[0].cbBuffer,
&pHello))
{
return(SEC_E_INVALID_TOKEN);
}
#if DBG
DebugLog((DEB_TRACE, "Hello = %x\n", pHello));
DebugLog((DEB_TRACE, " Session ID hit \t%s\n", pHello->SessionIdHit ? "Yes" : "No"));
DebugLog((DEB_TRACE, " Certificate Type\t%d\n", pHello->CertificateType));
DebugLog((DEB_TRACE, " Certificate Len\t%d\n", pHello->CertificateLength));
DebugLog((DEB_TRACE, " cCipherSpecs \t%d\n", pHello->cCipherSpecs));
DebugLog((DEB_TRACE, " ConnectionId \t%d\n", pHello->Connection.cbSessionId));
for (i = 0 ; i < pHello->cCipherSpecs ; i++ )
{
DebugLog((DEB_TRACE, " Cipher[%i] = %06x (%s)\n", i, pHello->pCipherSpecs[i],
DbgGetNameOfCrypto(pHello->pCipherSpecs[i]) ));
}
#endif
switch (pHello->CertificateType)
{
case SSL_CT_X509_CERTIFICATE:
if (!CrackCertificate( pHello->pCertificate,
pHello->CertificateLength,
TRUE,
&pCertificate))
{
return(SEC_E_INVALID_TOKEN);
}
break;
default:
return( SEC_E_INVALID_TOKEN ); // BUGBUG: Generate error msg
}
pContext->pCertificate = pCertificate;
#if DBG
DebugLog((DEB_TRACE, "Certificate = %x\n", pCertificate));
DebugLog((DEB_TRACE, " Version = %d\n", pCertificate->Version));
DebugLog((DEB_TRACE, " Serial Number = %d : %d\n",
pCertificate->SerialNumber[0], pCertificate->SerialNumber[1]));
DebugLog((DEB_TRACE, " AlgId = %d, %s\n", pCertificate->SignatureAlgorithm,
AlgName(pCertificate->SignatureAlgorithm)));
DebugLog((DEB_TRACE, " Issuer = %s\n", pCertificate->pszIssuer));
DebugLog((DEB_TRACE, " Subject = %s\n", pCertificate->pszSubject));
DebugLog((DEB_TRACE, " Public Key\n"));
DebugLog((DEB_TRACE, " keylen = %d\n", pCertificate->pPublicKey->keylen));
DebugLog((DEB_TRACE, " bitlen = %d\n", pCertificate->pPublicKey->bitlen));
DebugLog((DEB_TRACE, " datalen = %d\n", pCertificate->pPublicKey->datalen));
DebugLog((DEB_TRACE, " exponent = %d\n", pCertificate->pPublicKey->pubexp));
#endif
// BUGBUG: Need to correctly select alg and key
SslGenerateRandomBits(pContext->MasterKey, 16);
pContext->ServerSessionId = pHello->Connection;
pContext->pSystem = &csRC4;
pContext->pCheck = &ckMD5;
scRet = MakeSessionKeys(pContext, 16 * 8 );
Key.CipherKind = pHello->pCipherSpecs[0];
if (Key.CipherKind == CRYPTO_RC4_40)
{
Key.ClearKeyLen = 11;
CopyMemory(Key.ClearKey, pContext->MasterKey, 11);
pPortionToEncrypt = &pContext->MasterKey[11];
BytesToEncrypt = 5;
}
else
{
Key.ClearKeyLen = 0;
pPortionToEncrypt = pContext->MasterKey;
BytesToEncrypt = 16;
}
Key.KeyArgLen = 0;
pBuffer = pOutput->pBuffers;
if (pContext->ContextAttr & ISC_REQ_ALLOCATE_MEMORY)
{
pBuffer->pvBuffer = NULL;
pBuffer->cbBuffer = 0;
*pfContextAttr = ISC_RET_ALLOCATED_MEMORY;
}
//
// ok, we have the master key. Now, encrypt it with the
// public key we got from our friends on the net...
//
Key.EncryptedKeyLen = ENCRYPTED_KEY_SIZE;
if (!PkcsPublicEncrypt( pPortionToEncrypt,
BytesToEncrypt,
pCertificate->pPublicKey,
NETWORK_ORDER,
Key.EncryptedKey,
&Key.EncryptedKeyLen))
{
//
// Clean Up
//
return( SEC_E_NO_AUTHENTICATING_AUTHORITY );
}
fPack = PackClientMasterKey(&Key,
(PSsl_Client_Master_Key *) &pBuffer->pvBuffer,
&pBuffer->cbBuffer);
pContext->WriteCounter++;
pBuffer->BufferType = SECBUFFER_TOKEN;
SslFree( pHello );
if (fPack)
{
pContext->Flags |= CONTEXT_FLAG_KEY;
return(SEC_I_CONTINUE_NEEDED);
}
return(SEC_E_INVALID_TOKEN);
}
SECURITY_STATUS
SslHandleServerVerify(
PSslContext pContext,
PSecBufferDesc pInput,
PCtxtHandle phNewContext,
PSecBufferDesc pOutput,
unsigned long SEC_FAR * pfContextAttr,
PTimeStamp ptsExpiry
)
{
SECURITY_STATUS scRet;
CtxtHandle hContext;
SecBuffer Buffers[3];
SecBufferDesc Desc;
PSsl_Server_Verify pVerify;
DWORD HeaderSize;
PSecBuffer pBuffer;
PSsl_Client_Finished pFinish;
*pfContextAttr = 0;
hContext.dwUpper = (DWORD) pContext;
hContext.dwLower = 0;
pContext->ReadCounter = 1;
pContext->WriteCounter = 2;
Desc.pBuffers = Buffers;
Desc.ulVersion = SECBUFFER_VERSION;
Desc.cBuffers = 3;
Buffers[0] = pInput->pBuffers[0];
Buffers[0].BufferType = SECBUFFER_DATA;
Buffers[1].BufferType = SECBUFFER_EMPTY;
Buffers[2].BufferType = SECBUFFER_EMPTY;
scRet = SslUnsealMessage( &hContext,
&Desc,
0,
NULL );
if (FAILED( scRet ) )
{
return(scRet);
}
if (Buffers[1].BufferType != SECBUFFER_DATA)
{
return( SEC_E_INTERNAL_ERROR );
}
pVerify = Buffers[1].pvBuffer;
if ((pVerify->MessageId != SSL_MT_SERVER_VERIFY) ||
(Buffers[1].cbBuffer > sizeof(Ssl_Server_Verify) ) )
{
return( SEC_E_INVALID_TOKEN );
}
if (memcmp( pVerify->ChallengeData,
pContext->Challenge,
pContext->ChallengeLength) )
{
return( SEC_E_INVALID_TOKEN );
}
//
// Ok, the server checked out. Now, generate the reply message:
//
HeaderSize = (pContext->Flags & CONTEXT_FLAG_BLOCK) ?
sizeof(Ssl_Message_Header_Ex) :
sizeof(Ssl_Message_Header);
Buffers[0].BufferType = SECBUFFER_TOKEN;
Buffers[0].cbBuffer = HeaderSize;
Buffers[1].BufferType = SECBUFFER_DATA;
Buffers[1].cbBuffer = sizeof(Ssl_Client_Finished);
pBuffer = pOutput->pBuffers;
if (pContext->ContextAttr & ISC_REQ_ALLOCATE_MEMORY)
{
pBuffer->cbBuffer = Buffers[0].cbBuffer + Buffers[1].cbBuffer;
pBuffer->pvBuffer = SslExternalAlloc( pBuffer->cbBuffer );
*pfContextAttr = ISC_RET_ALLOCATED_MEMORY;
if (!pBuffer->pvBuffer)
{
return( SEC_E_INSUFFICIENT_MEMORY );
}
}
else
{
if (pBuffer->cbBuffer < Buffers[0].cbBuffer + Buffers[1].cbBuffer)
{
return( SEC_E_INSUFFICIENT_MEMORY );
}
else
{
pBuffer->cbBuffer = Buffers[0].cbBuffer + Buffers[1].cbBuffer;
}
}
Buffers[0].pvBuffer = pBuffer->pvBuffer;
Buffers[1].pvBuffer = (PUCHAR) Buffers[0].pvBuffer + Buffers[0].cbBuffer;
Desc.cBuffers = 2;
pFinish = (PSsl_Client_Finished) Buffers[1].pvBuffer;
pFinish->MessageId = SSL_MT_CLIENT_FINISHED_V2;
CopyMemory( pFinish->ConnectionId,
pContext->ServerSessionId.bSessionId,
pContext->ServerSessionId.cbSessionId );
scRet = SslSealMessage( &hContext,
0,
&Desc,
0 );
if (FAILED( scRet ) )
{
return( scRet );
}
pContext->Flags |= CONTEXT_FLAG_VERIFY;
*pfContextAttr |= ISC_RET_INTERMEDIATE_RETURN;
return( SEC_I_CONTINUE_NEEDED );
}
SECURITY_STATUS
SslHandleServerFinish(
PSslContext pContext,
PSecBufferDesc pInput,
PCtxtHandle phNewContext,
PSecBufferDesc pOutput,
unsigned long SEC_FAR * pfContextAttr,
PTimeStamp ptsExpiry
)
{
SECURITY_STATUS scRet;
CtxtHandle hContext;
SecBuffer Buffers[3];
SecBufferDesc Desc;
PSsl_Server_Finished pFinished;
DWORD HeaderSize;
PSecBuffer pBuffer;
hContext.dwUpper = (DWORD) pContext;
hContext.dwLower = 0;
Desc.pBuffers = Buffers;
Desc.ulVersion = SECBUFFER_VERSION;
Desc.cBuffers = 3;
Buffers[0] = pInput->pBuffers[0];
Buffers[0].BufferType = SECBUFFER_DATA;
Buffers[1].BufferType = SECBUFFER_EMPTY;
Buffers[2].BufferType = SECBUFFER_EMPTY;
scRet = SslUnsealMessage( &hContext,
&Desc,
0,
NULL );
if (FAILED( scRet ) )
{
return(scRet);
}
if (Buffers[1].BufferType != SECBUFFER_DATA)
{
return( SEC_E_INTERNAL_ERROR );
}
pFinished = Buffers[1].pvBuffer;
if (pFinished->MessageId != SSL_MT_SERVER_FINISHED_V2)
{
return( SEC_E_INVALID_TOKEN );
}
CopyMemory( pContext->ServerSessionId.bSessionId,
pFinished->SessionId,
Buffers[1].cbBuffer - 1);
*pfContextAttr = ISC_RET_CONFIDENTIALITY | ISC_RET_STREAM ;
return( SEC_E_OK );
}
SECURITY_STATUS SEC_ENTRY
SslInitializeSecurityContextW(
PCredHandle phCredential, // Cred to base context
PCtxtHandle phContext, // Existing context (OPT)
SEC_WCHAR SEC_FAR * pszTargetName, // Name of target
unsigned long fContextReq, // Context Requirements
unsigned long Reserved1, // Reserved, MBZ
unsigned long TargetDataRep, // Data rep of target
PSecBufferDesc pInput, // Input Buffers
unsigned long Reserved2, // Reserved, MBZ
PCtxtHandle phNewContext, // (out) New Context handle
PSecBufferDesc pOutput, // (inout) Output Buffers
unsigned long SEC_FAR * pfContextAttr, // (out) Context attrs
PTimeStamp ptsExpiry // (out) Life span (OPT)
)
{
PCHAR pszAnsiTarget;
DWORD cchTarget;
SECURITY_STATUS scRet;
if (pszTargetName)
{
cchTarget = wcslen(pszTargetName) + 1;
pszAnsiTarget = SslAlloc('isnA', LMEM_FIXED, cchTarget * 2);
if (!pszAnsiTarget)
{
return(SEC_E_INSUFFICIENT_MEMORY);
}
WideCharToMultiByte(
CP_ACP, 0,
pszTargetName, cchTarget,
pszAnsiTarget, cchTarget * 2,
NULL, NULL );
}
else
{
pszAnsiTarget = NULL;
}
scRet = SslInitializeSecurityContextA(
phCredential,
phContext,
pszAnsiTarget,
fContextReq,
Reserved1,
TargetDataRep,
pInput,
Reserved2,
phNewContext,
pOutput,
pfContextAttr,
ptsExpiry );
if (pszAnsiTarget)
{
SslFree(pszAnsiTarget);
}
}
SECURITY_STATUS SEC_ENTRY
SslInitializeSecurityContextA(
PCredHandle phCredential, // Cred to base context
PCtxtHandle phContext, // Existing context (OPT)
SEC_CHAR SEC_FAR * pszTargetName, // Name of target
unsigned long fContextReq, // Context Requirements
unsigned long Reserved1, // Reserved, MBZ
unsigned long TargetDataRep, // Data rep of target
PSecBufferDesc pInput, // Input Buffers
unsigned long Reserved2, // Reserved, MBZ
PCtxtHandle phNewContext, // (out) New Context handle
PSecBufferDesc pOutput, // (inout) Output Buffers
unsigned long SEC_FAR * pfContextAttr, // (out) Context attrs
PTimeStamp ptsExpiry // (out) Life span (OPT)
)
{
PSslContext pContext;
PSslCredential pCred;
Client_Hello HelloMessage;
PSecBuffer pBuffer;
BOOL fPack;
if (Reserved1 || Reserved2)
{
return( SEC_E_UNSUPPORTED_FUNCTION );
}
if (!CryptoOk)
{
return( SEC_E_UNSUPPORTED_FUNCTION );
}
pContext = SslpValidateContextHandle(phContext);
if (pContext)
{
if (pContext->Flags & CONTEXT_FLAG_VERIFY)
{
return SslHandleServerFinish(
pContext,
pInput,
phNewContext,
pOutput,
pfContextAttr,
ptsExpiry );
}
if (pContext->Flags & CONTEXT_FLAG_KEY)
{
return SslHandleServerVerify(
pContext,
pInput,
phNewContext,
pOutput,
pfContextAttr,
ptsExpiry );
}
return SslHandleServerHello(
pContext,
pInput,
phNewContext,
pOutput,
pfContextAttr,
ptsExpiry);
}
pCred = SslpValidateCredentialHandle(phCredential);
if (!pCred)
{
return(SEC_E_INVALID_HANDLE);
}
if (!pOutput)
{
return(SEC_E_INVALID_TOKEN);
}
if (pOutput->cBuffers < 1)
{
return(SEC_E_INVALID_TOKEN);
}
fContextReq &= VALID_REQUEST_FLAGS;
HelloMessage.pCipherSpecs = SslAvailableCiphers;
HelloMessage.cCipherSpecs = SslNumberAvailableCiphers;
HelloMessage.SessionId.cbSessionId = 0;
pBuffer = pOutput->pBuffers;
if (fContextReq & ISC_REQ_ALLOCATE_MEMORY)
{
pBuffer->pvBuffer = NULL;
pBuffer->cbBuffer = 0;
*pfContextAttr = ISC_RET_ALLOCATED_MEMORY;
}
pContext = SslCreateContext();
if (!pContext)
{
return(SEC_E_INSUFFICIENT_MEMORY);
}
if (pszTargetName)
{
pContext->pszName = CopyString(pszTargetName);
}
pContext->ContextAttr = fContextReq;
pContext->pCred = pCred;
pContext->Flags = CONTEXT_FLAG_OUTBOUND;
SslReferenceCredential(pCred);
pContext->ChallengeLength = 16; // BUGBUG
SslGenerateRandomBits(
pContext->Challenge,
pContext->ChallengeLength );
HelloMessage.Challenge.cbChallenge = pContext->ChallengeLength;
RtlCopyMemory( HelloMessage.Challenge.bChallenge,
pContext->Challenge,
HelloMessage.Challenge.cbChallenge );
fPack = PackClientHello(&HelloMessage,
(PSsl_Client_Hello *) &pBuffer->pvBuffer,
&pBuffer->cbBuffer);
pBuffer->BufferType = SECBUFFER_TOKEN;
if (fPack)
{
phNewContext->dwUpper = (DWORD) pContext;
return(SEC_I_CONTINUE_NEEDED);
}
SslDeleteContext( pContext );
return(SEC_E_INSUFFICIENT_MEMORY);
}
SECURITY_STATUS SEC_ENTRY
SslHandleClientMasterKey(
PSslContext pContext,
PSecBufferDesc pInput,
PCtxtHandle phNewContext,
PSecBufferDesc pOutput,
unsigned long SEC_FAR * pfContextAttr,
PTimeStamp ptsExpiry
)
{
SECURITY_STATUS scRet;
PClient_Master_Key pMasterKey;
PCSystems pSystem;
DWORD i;
DWORD EncryptedLen;
BOOL fPack;
PSecBuffer pBuffer;
CtxtHandle hContext;
SecBuffer Buffers[3];
SecBufferDesc Desc;
DWORD HeaderSize;
PSsl_Server_Verify pVerify;
if (!pOutput)
{
return(SEC_E_INVALID_TOKEN);
}
if (pOutput->cBuffers < 1)
{
return(SEC_E_INVALID_TOKEN);
}
if (!UnpackClientMasterKey(
(PSsl_Client_Master_Key) pInput->pBuffers[0].pvBuffer,
pInput->pBuffers[0].cbBuffer,
&pMasterKey))
{
return( SEC_E_INVALID_TOKEN );
}
//
// Validate Client Response
//
pSystem = NULL;
for (i = 0; i < sizeof(ValidSystems) / sizeof(CSystems) ; i++ )
{
if (ValidSystems[i].CipherSpec == pMasterKey->CipherKind)
{
pSystem = &ValidSystems[i];
break;
}
}
if (! pSystem)
{
SslFree( pMasterKey );
return( SEC_E_INVALID_TOKEN );
}
DebugLog((DEB_TRACE, "Selected system %#x: clear = %d, cipher=%d, bits=%d\n",
pSystem->CipherSpec, pSystem->ClearKeyLen,
pSystem->EncryptedKeyLen, pSystem->Bits ));
if (pMasterKey->ClearKeyLen != pSystem->ClearKeyLen)
{
SslFree( pMasterKey );
return( SEC_E_INVALID_TOKEN );
}
pContext->pCSystem = pSystem;
CopyMemory( pContext->MasterKey,
pMasterKey->ClearKey,
pMasterKey->ClearKeyLen);
if (!PkcsPrivateDecrypt(pMasterKey->EncryptedKey,
pMasterKey->EncryptedKeyLen,
pContext->pCred->pPrivateKey,
NETWORK_ORDER,
&pContext->MasterKey[pMasterKey->ClearKeyLen],
&EncryptedLen ) )
{
SslFree( pMasterKey );
return( SEC_E_INVALID_TOKEN );
}
SslFree( pMasterKey );
if (EncryptedLen != pSystem->EncryptedKeyLen)
{
DebugLog((DEB_TRACE, "Invalid Encrypted Key Length: %#x\n", EncryptedLen));
return( SEC_E_INVALID_TOKEN );
}
pContext->pSystem = &csRC4;
pContext->pCheck = &ckMD5;
MakeSessionKeys( pContext, pSystem->Bits );
hContext.dwUpper = (DWORD) pContext;
hContext.dwLower = 0;
pContext->WriteCounter = 1;
pContext->ReadCounter = 2;
Desc.pBuffers = Buffers;
Desc.ulVersion = SECBUFFER_VERSION;
Desc.cBuffers = 2;
HeaderSize = (pContext->Flags & CONTEXT_FLAG_BLOCK) ?
sizeof(Ssl_Message_Header_Ex) :
sizeof(Ssl_Message_Header);
Buffers[0].BufferType = SECBUFFER_TOKEN;
Buffers[0].cbBuffer = HeaderSize;
Buffers[1].BufferType = SECBUFFER_DATA;
Buffers[1].cbBuffer = 1 + pContext->ChallengeLength;
pBuffer = pOutput->pBuffers;
if (pContext->ContextAttr & ISC_REQ_ALLOCATE_MEMORY)
{
pBuffer->cbBuffer = Buffers[0].cbBuffer + Buffers[1].cbBuffer;
pBuffer->pvBuffer = SslExternalAlloc( pBuffer->cbBuffer );
*pfContextAttr = ISC_RET_ALLOCATED_MEMORY;
if (!pBuffer->pvBuffer)
{
return( SEC_E_INSUFFICIENT_MEMORY );
}
}
else
{
if (pBuffer->cbBuffer < Buffers[0].cbBuffer + Buffers[1].cbBuffer)
{
return( SEC_E_INSUFFICIENT_MEMORY );
}
else
{
pBuffer->cbBuffer = Buffers[0].cbBuffer + Buffers[1].cbBuffer;
}
}
Buffers[0].pvBuffer = pBuffer->pvBuffer;
Buffers[1].pvBuffer = (PUCHAR) Buffers[0].pvBuffer + Buffers[0].cbBuffer;
Desc.cBuffers = 2;
pVerify = Buffers[1].pvBuffer;
pVerify->MessageId = SSL_MT_SERVER_VERIFY;
CopyMemory( pVerify->ChallengeData,
pContext->Challenge,
pContext->ChallengeLength );
scRet = SslSealMessage( &hContext,
0,
&Desc,
0 );
if (FAILED( scRet ) )
{
return( scRet );
}
pContext->Flags |= CONTEXT_FLAG_VERIFY;
return( SEC_I_CONTINUE_NEEDED );
}
SECURITY_STATUS SEC_ENTRY
SslHandleClientFinished(
PSslContext pContext,
PSecBufferDesc pInput,
PCtxtHandle phNewContext,
PSecBufferDesc pOutput,
unsigned long SEC_FAR * pfContextAttr,
PTimeStamp ptsExpiry
)
{
SECURITY_STATUS scRet;
CtxtHandle hContext;
SecBuffer Buffers[3];
SecBufferDesc Desc;
PSsl_Client_Finished pFinished;
PSsl_Server_Finished pFinish;
DWORD HeaderSize;
PSecBuffer pBuffer;
*pfContextAttr = 0;
hContext.dwUpper = (DWORD) pContext;
hContext.dwLower = 0;
Desc.pBuffers = Buffers;
Desc.ulVersion = SECBUFFER_VERSION;
Desc.cBuffers = 3;
Buffers[0] = pInput->pBuffers[0];
Buffers[0].BufferType = SECBUFFER_DATA;
Buffers[1].BufferType = SECBUFFER_EMPTY;
Buffers[2].BufferType = SECBUFFER_EMPTY;
scRet = SslUnsealMessage( &hContext,
&Desc,
0,
NULL );
if (FAILED( scRet ) )
{
return(scRet);
}
if (Buffers[1].BufferType != SECBUFFER_DATA)
{
return( SEC_E_INTERNAL_ERROR );
}
pFinished = Buffers[1].pvBuffer;
if (pFinished->MessageId != SSL_MT_CLIENT_FINISHED_V2)
{
return( SEC_E_INVALID_TOKEN );
}
#if 0
//
// had problems building using RtlEqualMemory, why?
//
if (!RtlEqualMemory(pFinished->ConnectionId,
pContext->ServerSessionId.bSessionId,
pContext->ServerSessionId.cbSessionId))
{
return( SEC_E_INVALID_TOKEN );
}
#else
if ( memcmp(pFinished->ConnectionId,
pContext->ServerSessionId.bSessionId,
pContext->ServerSessionId.cbSessionId))
{
return( SEC_E_INVALID_TOKEN );
}
#endif
hContext.dwUpper = (DWORD) pContext;
hContext.dwLower = 0;
Desc.pBuffers = Buffers;
Desc.ulVersion = SECBUFFER_VERSION;
Desc.cBuffers = 2;
HeaderSize = (pContext->Flags & CONTEXT_FLAG_BLOCK) ?
sizeof(Ssl_Message_Header_Ex) :
sizeof(Ssl_Message_Header);
Buffers[0].BufferType = SECBUFFER_TOKEN;
Buffers[0].cbBuffer = HeaderSize;
Buffers[1].BufferType = SECBUFFER_DATA;
Buffers[1].cbBuffer = sizeof(Ssl_Server_Finished);
pBuffer = pOutput->pBuffers;
if (pContext->ContextAttr & ASC_REQ_ALLOCATE_MEMORY)
{
pBuffer->cbBuffer = Buffers[0].cbBuffer + Buffers[1].cbBuffer;
pBuffer->pvBuffer = SslExternalAlloc( pBuffer->cbBuffer );
*pfContextAttr = ASC_RET_ALLOCATED_MEMORY;
if (!pBuffer->pvBuffer)
{
return( SEC_E_INSUFFICIENT_MEMORY );
}
}
else
{
if (pBuffer->cbBuffer < Buffers[0].cbBuffer + Buffers[1].cbBuffer)
{
return( SEC_E_INSUFFICIENT_MEMORY );
}
else
{
pBuffer->cbBuffer = Buffers[0].cbBuffer + Buffers[1].cbBuffer;
}
}
Buffers[0].pvBuffer = pBuffer->pvBuffer;
Buffers[1].pvBuffer = (PUCHAR) Buffers[0].pvBuffer + Buffers[0].cbBuffer;
Desc.cBuffers = 2;
pFinish = Buffers[1].pvBuffer;
pFinish->MessageId = SSL_MT_SERVER_FINISHED_V2;
CopyMemory( pFinish->SessionId,
pContext->ServerSessionId.bSessionId,
pContext->ServerSessionId.cbSessionId );
scRet = SslSealMessage( &hContext,
0,
&Desc,
0 );
if (FAILED( scRet ) )
{
return( scRet );
}
*pfContextAttr |= ASC_RET_CONFIDENTIALITY | ASC_RET_STREAM;
pContext->Flags |= CONTEXT_FLAG_FINISH;
return( SEC_E_OK );
}
SECURITY_STATUS SEC_ENTRY
SslAcceptSecurityContext(
PCredHandle phCredential, // Cred to base context
PCtxtHandle phContext, // Existing context (OPT)
PSecBufferDesc pInput, // Input buffer
unsigned long fContextReq, // Context Requirements
unsigned long TargetDataRep, // Target Data Rep
PCtxtHandle phNewContext, // (out) New context handle
PSecBufferDesc pOutput, // (inout) Output buffers
unsigned long SEC_FAR * pfContextAttr, // (out) Context attributes
PTimeStamp ptsExpiry // (out) Life span (OPT)
)
{
PSslContext pContext;
PSslCredential pCred;
PSecBuffer pBuffer;
Server_Hello Reply;
PClient_Hello pHello;
BOOL fPack;
BOOL fCached;
DWORD RequiredSpace;
CtxtHandle hContext;
SecBufferDesc Desc;
SecBuffer Buffers[3];
PSsl_Server_Verify pVerify;
SECURITY_STATUS scRet;
CipherSpec CommonCiphers[16];
DWORD cCommonCiphers;
DWORD ClientCipher;
DWORD ServerCipher;
#if DBG
DWORD i;
#endif
#if ENABLE_TIMERS
LONGLONG StartTime;
LONGLONG EndTime;
LONGLONG Freq;
NtQueryPerformanceCounter((PLARGE_INTEGER) &StartTime,
(PLARGE_INTEGER) &Freq);
#endif
if (!CryptoOk)
{
return( SEC_E_UNSUPPORTED_FUNCTION );
}
pContext = SslpValidateContextHandle(phContext);
if (pContext)
{
if (pContext->Flags & CONTEXT_FLAG_VERIFY)
{
scRet = SslHandleClientFinished(
pContext,
pInput,
phNewContext,
pOutput,
pfContextAttr,
ptsExpiry );
}
else if (pContext->Flags & CONTEXT_FLAG_HELLO)
{
scRet = SslHandleClientMasterKey(
pContext,
pInput,
phNewContext,
pOutput,
pfContextAttr,
ptsExpiry );
}
else
{
scRet = SEC_E_UNSUPPORTED_FUNCTION;
}
#if ENABLE_TIMERS
NtQueryPerformanceCounter((PLARGE_INTEGER) &EndTime, NULL);
DebugLog((DEB_TRACE_PERF, "Op took %d intervals of %d\n",
(LONG)(EndTime - StartTime),
(LONG)(Freq) ));
#endif
return( scRet );
}
pCred = SslpValidateCredentialHandle(phCredential);
if (!pCred)
{
return( SEC_E_INVALID_HANDLE );
}
if (!pOutput || !pOutput)
{
return( SEC_E_INVALID_TOKEN );
}
if (pOutput->cBuffers < 1)
{
return( SEC_E_INVALID_TOKEN );
}
if (pInput->cBuffers < 1)
{
return( SEC_E_INVALID_TOKEN );
}
fContextReq &= VALID_REQUEST_FLAGS;
pBuffer = &pInput->pBuffers[0]; // BUGBUG: Find DATA
if (!UnpackClientHello( TRUE,
(PSsl_Client_Hello) pBuffer->pvBuffer,
pBuffer->cbBuffer,
&pHello ) )
{
DebugLog((DEB_TRACE, "Invalid hello message\n"));
return( SEC_E_INVALID_TOKEN );
}
#if DBG
DebugLog((DEB_TRACE, "Client Hello at %x\n", pHello));
DebugLog((DEB_TRACE, " CipherSpecs %d\n", pHello->cCipherSpecs));
for (i = 0 ; i < pHello->cCipherSpecs ; i++ )
{
DebugLog((DEB_TRACE, " Cipher[%i] = %06x (%s)\n", i, pHello->pCipherSpecs[i],
DbgGetNameOfCrypto(pHello->pCipherSpecs[i]) ));
}
DebugLog((DEB_TRACE, " ChallengeLength = %d\n", pHello->Challenge.cbChallenge));
#endif
//
// Build server side context:
//
pBuffer = pOutput->pBuffers;
if (fContextReq & ISC_REQ_ALLOCATE_MEMORY)
{
pBuffer->pvBuffer = NULL;
pBuffer->cbBuffer = 0;
*pfContextAttr = ISC_RET_ALLOCATED_MEMORY;
}
ZeroMemory( &Reply, sizeof( Reply ) );
//
// Now, see what we can find:
//
pContext = NULL;
fCached = FALSE;
if (pHello->SessionId.cbSessionId)
{
pContext = SslFindSession( &pHello->SessionId );
//
// BUGBUG: Until we can precisely determine how session id reuse
// works (as opposed to is spec'd), this is turned off:
//
pContext = NULL;
#if 0
if (pContext)
{
DebugLog((DEB_TRACE, "Found context in cache\n"));
pContext->Flags = CONTEXT_FLAG_HELLO | CONTEXT_FLAG_VERIFY;
Reply.SessionIdHit = 1;
Reply.Connection = pContext->ServerSessionId;
pContext->ReadCounter = 0;
pContext->WriteCounter = 1;
fCached = TRUE ;
MakeSessionKeys( pContext, pContext->pCSystem->Bits );
}
#endif
}
//
// Calculate common ciphers:
//
cCommonCiphers = 0;
for (ServerCipher = 0;
ServerCipher < SslNumberAvailableCiphers ;
ServerCipher++)
{
for (ClientCipher = 0;
ClientCipher < pHello->cCipherSpecs ;
ClientCipher++ )
{
if ( SslAvailableCiphers[ServerCipher] ==
pHello->pCipherSpecs[ClientCipher] )
{
CommonCiphers[cCommonCiphers++] = SslAvailableCiphers[ServerCipher];
break;
}
}
}
//
// if cCommonCipers == 0, then we have none in common. At this point, we
// should generate an error response, but that is for later. For now,
// we will generate an invalid_token return, and bail out.
//
if (cCommonCiphers == 0)
{
SslFree( pHello );
return( SEC_E_INVALID_TOKEN );
}
if ( !pContext )
{
pContext = SslCreateContext();
if (!pContext)
{
SslFree( pHello );
return(SEC_E_INSUFFICIENT_MEMORY);
}
pContext->ContextAttr = fContextReq;
SslReferenceCredential(pCred);
pContext->pCred = pCred;
pContext->Flags = 0;
Reply.SessionIdHit = 0;
Reply.CertificateType = SSL_CT_X509_CERTIFICATE;
Reply.CertificateLength = pCred->cbCertificate;
Reply.cCipherSpecs = cCommonCiphers;
Reply.pCipherSpecs = CommonCiphers;
Reply.Connection.cbSessionId = 16;
SslGenerateRandomBits( Reply.Connection.bSessionId,
Reply.Connection.cbSessionId );
pContext->ServerSessionId = Reply.Connection;
Reply.pCertificate = pCred->pCertificate;
}
CopyMemory( pContext->Challenge,
pHello->Challenge.bChallenge,
pHello->Challenge.cbChallenge );
pContext->ChallengeLength = pHello->Challenge.cbChallenge;
if ( fCached )
{
fPack = PackServerHello( &Reply, NULL, &RequiredSpace );
RequiredSpace += pContext->ChallengeLength + 1;
RequiredSpace += sizeof( Ssl_Message_Header ) + 3;
pBuffer->pvBuffer = SslExternalAlloc( RequiredSpace );
if (pBuffer->pvBuffer)
{
pBuffer->cbBuffer= RequiredSpace;
fPack = PackServerHello(&Reply,
(PSsl_Server_Hello *) &pBuffer->pvBuffer,
&RequiredSpace );
//
// Ugly stuff. We actually jam the next message into the buffer
// as well.
//
Buffers[0].BufferType = SECBUFFER_TOKEN;
Buffers[0].cbBuffer = sizeof( Ssl_Message_Header );
Buffers[0].pvBuffer = (PVOID) ((PUCHAR) pBuffer->pvBuffer + RequiredSpace);
Buffers[1].BufferType = SECBUFFER_DATA;
Buffers[1].cbBuffer = 1 + pContext->ChallengeLength;
Buffers[1].pvBuffer = (PVOID) ((PUCHAR) Buffers[0].pvBuffer + Buffers[0].cbBuffer);
hContext.dwUpper = (DWORD) pContext;
hContext.dwLower = 0;
Desc.ulVersion = SECBUFFER_VERSION;
Desc.pBuffers = Buffers;
Desc.cBuffers = 2;
pVerify = Buffers[1].pvBuffer;
pVerify->MessageId = SSL_MT_SERVER_VERIFY;
CopyMemory( pVerify->ChallengeData,
pContext->Challenge,
pContext->ChallengeLength );
scRet = SslSealMessage( &hContext,
0,
&Desc,
0 );
}
else
{
fPack = FALSE;
}
}
else
{
fPack = PackServerHello(&Reply,
(PSsl_Server_Hello *) &pBuffer->pvBuffer,
&pBuffer->cbBuffer);
}
pBuffer->BufferType = SECBUFFER_TOKEN;
SslFree( pHello );
#if ENABLE_TIMERS
NtQueryPerformanceCounter((PLARGE_INTEGER) &EndTime, NULL);
DebugLog((DEB_TRACE_PERF, "Op took %d intervals of %d\n",
(LONG)(EndTime - StartTime),
(LONG)(Freq) ));
#endif
if (fPack)
{
phNewContext->dwUpper = (DWORD) pContext;
pContext->Flags |= CONTEXT_FLAG_HELLO;
return(SEC_I_CONTINUE_NEEDED);
}
SslDeleteContext( pContext );
return(SEC_E_INSUFFICIENT_MEMORY);
}
SECURITY_STATUS SEC_ENTRY
SslDeleteSecurityContext(
PCtxtHandle phContext // Context to delete
)
{
PSslContext pContext;
pContext = SslpValidateContextHandle(phContext);
if ( !pContext )
{
return( SEC_E_INVALID_HANDLE );
}
if ((pContext->Flags & CONTEXT_FLAG_OUTBOUND) ||
((pContext->Flags & CONTEXT_FLAG_FINISH) == 0) )
{
SslDeleteContext( pContext );
return( SEC_E_OK );
}
#ifdef SESSION_RETRY_DONE
if ( (pContext->pReadState) && (pContext->pSystem) )
{
pContext->pSystem->Discard( &pContext->pReadState );
}
if ( (pContext->pWriteState) && (pContext->pSystem) )
{
pContext->pSystem->Discard( &pContext->pWriteState );
}
if ( (pContext->pReadBuffer) && (pContext->pCheck) )
{
pContext->pCheck->Finish( &pContext->pReadBuffer );
}
if ( (pContext->pWriteBuffer) && (pContext->pCheck) )
{
pContext->pCheck->Finish( &pContext->pWriteBuffer );
}
SslCacheSession( pContext );
#else
SslDeleteContext( pContext );
#endif
return( SEC_E_OK );
}
SECURITY_STATUS SEC_ENTRY
SslQueryContextAttributesA(
PCtxtHandle phContext, // Context to query
unsigned long ulAttribute, // Attribute to query
void SEC_FAR * pBuffer // Buffer for attributes
)
{
PSslContext pContext;
PSecPkgContext_Sizes pSizes;
PSecPkgContext_StreamSizes pStreamSize;
PSecPkgContext_Lifespan pLifeSpan;
PSecPkgContext_Names pNames;
PSecPkgContext_Authority pAuthority;
PSecPkgContext_KeyInfo pKeyInfo;
PX509Certificate pCert;
pContext = SslpValidateContextHandle( phContext );
if ( !pContext )
{
return( SEC_E_INVALID_HANDLE );
}
switch ( ulAttribute )
{
case SECPKG_ATTR_SIZES:
if (!pContext->pSystem)
{
return( SEC_E_INVALID_HANDLE );
}
pSizes = (PSecPkgContext_Sizes) pBuffer;
pSizes->cbMaxToken = 3 * 1024;
pSizes->cbMaxSignature = (pContext->Flags & CONTEXT_FLAG_BLOCK) ?
sizeof( Ssl_Message_Header_Ex ) :
sizeof( Ssl_Message_Header );
pSizes->cbBlockSize = pContext->pSystem->BlockSize;
pSizes->cbSecurityTrailer = pSizes->cbMaxSignature;
return( SEC_E_OK );
case SECPKG_ATTR_STREAM_SIZES:
if ( !pContext->pSystem )
{
return( SEC_E_INVALID_HANDLE );
}
pStreamSize = (PSecPkgContext_StreamSizes) pBuffer;
pStreamSize->cbHeader = (pContext->Flags & CONTEXT_FLAG_BLOCK) ?
sizeof( Ssl_Message_Header_Ex ) :
sizeof( Ssl_Message_Header );
pStreamSize->cbTrailer = 0;
pStreamSize->cbMaximumMessage = 0x3ffe;
pStreamSize->cBuffers = 4;
pStreamSize->cbBlockSize = (pContext->Flags & CONTEXT_FLAG_BLOCK) ?
8 : 1;
return( SEC_E_OK );
case SECPKG_ATTR_NAMES:
if ( !pContext->pCertificate )
{
return( SEC_E_UNSUPPORTED_FUNCTION );
}
pCert = pContext->pCertificate;
pNames = (PSecPkgContext_Names) pBuffer;
if ( pCert->pszSubject )
{
pNames->sUserName = SslExternalAlloc( strlen(pCert->pszSubject) + 1);
if (pNames->sUserName)
{
strcpy( pNames->sUserName, pCert->pszSubject );
return( SEC_E_OK );
}
return( SEC_E_INSUFFICIENT_MEMORY );
}
return( SEC_E_UNSUPPORTED_FUNCTION );
case SECPKG_ATTR_LIFESPAN:
if ( !pContext->pCertificate )
{
return( SEC_E_UNSUPPORTED_FUNCTION );
}
pCert = pContext->pCertificate;
pLifeSpan = (PSecPkgContext_Lifespan) pBuffer;
pLifeSpan->tsStart.QuadPart = *((LONGLONG *) &pCert->ValidFrom);
pLifeSpan->tsExpiry.QuadPart = *((LONGLONG*) &pCert->ValidUntil);
return( SEC_E_OK );
case SECPKG_ATTR_DCE_INFO:
return( SEC_E_UNSUPPORTED_FUNCTION );
case SECPKG_ATTR_KEY_INFO:
if ( (!pContext->pSystem) || (!pContext->pCSystem) )
{
return( SEC_E_UNSUPPORTED_FUNCTION );
}
pKeyInfo = (PSecPkgContext_KeyInfo) pBuffer;
pKeyInfo->KeySize = pContext->pCSystem->EncryptedKeyLen * 8;
pKeyInfo->sSignatureAlgorithmName = SslExternalAlloc(
strlen( pContext->pCheck->pszName ) + 1 );
if ( pKeyInfo->sSignatureAlgorithmName)
{
strcpy( pKeyInfo->sSignatureAlgorithmName,
pContext->pCheck->pszName );
}
else
{
return( SEC_E_INSUFFICIENT_MEMORY );
}
pKeyInfo->sEncryptAlgorithmName = SslExternalAlloc(
strlen( pContext->pSystem->pszName ) + 1 );
if ( pKeyInfo->sEncryptAlgorithmName )
{
strcpy( pKeyInfo->sEncryptAlgorithmName,
pContext->pSystem->pszName );
}
else
{
SslExternalFree( pKeyInfo->sSignatureAlgorithmName );
return( SEC_E_INSUFFICIENT_MEMORY );
}
return( SEC_E_OK );
case SECPKG_ATTR_AUTHORITY:
if ( !pContext->pCertificate )
{
return( SEC_E_UNSUPPORTED_FUNCTION );
}
pCert = (PX509Certificate) pContext->pCertificate;
pAuthority = (PSecPkgContext_Authority) pBuffer;
if ( pCert->pszSubject )
{
pAuthority->sAuthorityName = SslExternalAlloc( strlen(pCert->pszIssuer) + 1);
if (pAuthority->sAuthorityName )
{
strcpy( pAuthority->sAuthorityName, pCert->pszIssuer );
return( SEC_E_OK );
}
return( SEC_E_INSUFFICIENT_MEMORY );
}
return( SEC_E_UNSUPPORTED_FUNCTION );
default:
return( SEC_E_INVALID_TOKEN );
}
return( SEC_E_INVALID_TOKEN );
}
SECURITY_STATUS SEC_ENTRY
SslQueryContextAttributesW(
PCtxtHandle phContext, // Context to query
unsigned long ulAttribute, // Attribute to query
void SEC_FAR * pBuffer // Buffer for attributes
)
{
return( SslQueryContextAttributesA( phContext, ulAttribute, pBuffer ) );
}
SECURITY_STATUS SEC_ENTRY
SslImpersonateSecurityContext(
PCtxtHandle phContext // Context to impersonate
)
{
PSslContext pContext;
pContext = SslpValidateContextHandle( phContext );
if ( pContext )
{
return( SEC_E_NO_IMPERSONATION );
}
return( SEC_E_INVALID_HANDLE );
}
SECURITY_STATUS SEC_ENTRY
SslRevertSecurityContext(
PCtxtHandle phContext // Context from which to re
)
{
PSslContext pContext;
pContext = SslpValidateContextHandle( phContext );
if ( pContext )
{
return( SEC_E_NO_IMPERSONATION );
}
return( SEC_E_INVALID_HANDLE );
}