Leaked source code of windows server 2003
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.
 
 
 
 
 
 

2369 lines
67 KiB

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1995.
//
// File: ctxtattr.c
//
// Contents: QueryContextAttribute and related functions.
//
// Classes:
//
// Functions:
//
// History: 09-30-97 jbanes Created
//
//----------------------------------------------------------------------------
#include "sslp.h"
#include <ssl2msg.h>
#include <ssl3msg.h>
#include <pct1msg.h>
#include <tls1key.h>
#include <mapper.h>
#include <lsasecpk.h>
typedef struct {
DWORD dwProtoId;
LPCTSTR szProto;
DWORD dwMajor;
DWORD dwMinor;
} PROTO_ID;
const PROTO_ID rgProts[] = {
{ SP_PROT_SSL2_CLIENT, TEXT("SSL"), 2, 0 },
{ SP_PROT_SSL2_SERVER, TEXT("SSL"), 2, 0 },
{ SP_PROT_PCT1_CLIENT, TEXT("PCT"), 1, 0 },
{ SP_PROT_PCT1_SERVER, TEXT("PCT"), 1, 0 },
{ SP_PROT_SSL3_CLIENT, TEXT("SSL"), 3, 0 },
{ SP_PROT_SSL3_SERVER, TEXT("SSL"), 3, 0 },
{ SP_PROT_TLS1_CLIENT, TEXT("TLS"), 1, 0 },
{ SP_PROT_TLS1_SERVER, TEXT("TLS"), 1, 0 }
};
//+-------------------------------------------------------------------------
//
// Function: SpQueryAccessToken
//
// Synopsis: Retrieves the SECPKG_ATTR_ACCESS_TOKEN context attribute.
//
// Arguments:
//
// Returns:
//
// Notes: The buffer returned contains the following structure:
//
// typedef struct _SecPkgContext_AccessToken
// {
// void SEC_FAR * AccessToken;
// } SecPkgContext_AccessToken, SEC_FAR * PSecPkgContext_AccessToken;
//
//--------------------------------------------------------------------------
SECURITY_STATUS
SpQueryAccessToken(
PSPContext pContext,
PSecPkgContext_AccessToken pAccessToken)
{
PSessCacheItem pZombie;
DebugLog((DEB_TRACE, "QueryContextAttributes(SECPKG_ATTR_ACCESS_TOKEN)\n"));
pZombie = pContext->RipeZombie;
if(pZombie == NULL ||
pZombie->hLocator == 0)
{
if(pZombie->LocatorStatus)
{
return(SP_LOG_RESULT(pZombie->LocatorStatus));
}
else
{
return(SP_LOG_RESULT(SEC_E_NO_IMPERSONATION));
}
}
pAccessToken->AccessToken = (VOID *)pZombie->hLocator;
return SEC_E_OK;
}
//+-------------------------------------------------------------------------
//
// Function: SpQueryAuthority
//
// Synopsis: Retrieves the SECPKG_ATTR_AUTHORITY context attribute.
//
// Arguments:
//
// Returns:
//
// Notes: The buffer returned contains the following structure:
//
// typedef struct _SecPkgContext_AuthorityW
// {
// SEC_WCHAR SEC_FAR * sAuthorityName;
// } SecPkgContext_AuthorityW, * PSecPkgContext_AuthorityW;
//
//--------------------------------------------------------------------------
SECURITY_STATUS
SpQueryAuthority(
LSA_SEC_HANDLE ContextHandle,
PVOID Buffer)
{
SecPkgContext_Authority Authority;
DWORD Size;
PSPContext pContext;
SECURITY_STATUS Status;
PVOID pvClient = NULL;
CERT_CONTEXT * pCert;
DWORD cchIssuer;
DWORD cbIssuer;
DebugLog((DEB_TRACE, "QueryContextAttributes(SECPKG_ATTR_AUTHORITY)\n"));
pContext = (PSPContext)ContextHandle;
Size = sizeof( SecPkgContext_Authority );
//
// Obtain data from Schannel.
//
pCert = pContext->RipeZombie->pRemoteCert;
if(NULL == pCert)
{
return SP_LOG_RESULT(SEC_E_UNSUPPORTED_FUNCTION);
}
if(pCert->pCertInfo->Issuer.cbData == 0 ||
pCert->pCertInfo->Issuer.pbData == NULL)
{
return SP_LOG_RESULT(SEC_E_UNSUPPORTED_FUNCTION);
}
if(0 >= (cchIssuer = CertNameToStr(pCert->dwCertEncodingType,
&pCert->pCertInfo->Issuer,
CERT_X500_NAME_STR | CERT_NAME_STR_NO_PLUS_FLAG,
NULL,
0)))
{
return SP_LOG_RESULT(SEC_E_UNSUPPORTED_FUNCTION);
}
cbIssuer = (cchIssuer + 1) * sizeof(TCHAR);
Authority.sAuthorityName = SPExternalAlloc(cbIssuer);
if(Authority.sAuthorityName == NULL)
{
return SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
}
if(0 >= CertNameToStr(pCert->dwCertEncodingType,
&pCert->pCertInfo->Issuer,
CERT_X500_NAME_STR | CERT_NAME_STR_NO_PLUS_FLAG,
Authority.sAuthorityName,
cchIssuer))
{
SPExternalFree(Authority.sAuthorityName);
return SP_LOG_RESULT(SEC_E_UNSUPPORTED_FUNCTION);
}
//
// Copy buffers to client memory.
//
Status = LsaTable->AllocateClientBuffer(
NULL,
cbIssuer,
&pvClient);
if(FAILED(Status))
{
SPExternalFree(Authority.sAuthorityName);
return SP_LOG_RESULT(Status);
}
Status = LsaTable->CopyToClientBuffer(
NULL,
cbIssuer,
pvClient,
Authority.sAuthorityName);
if(FAILED(Status))
{
SPExternalFree(Authority.sAuthorityName);
LsaTable->FreeClientBuffer(NULL, pvClient);
return SP_LOG_RESULT(Status);
}
SPExternalFree(Authority.sAuthorityName);
Authority.sAuthorityName = pvClient;
//
// Copy structure back to client memory.
//
Status = LsaTable->CopyToClientBuffer( NULL,
Size,
Buffer,
&Authority );
if(FAILED(Status))
{
LsaTable->FreeClientBuffer(NULL, pvClient);
return SP_LOG_RESULT(Status);
}
return SEC_E_OK;
}
//+-------------------------------------------------------------------------
//
// Function: SpQueryConnectionInfo
//
// Synopsis: Retrieves the SECPKG_ATTR_CONNECTION_INFO context attribute.
//
// Arguments:
//
// Returns:
//
// Notes: The buffer returned contains the following structure:
//
// typedef struct _SecPkgContext_ConnectionInfo
// {
// DWORD dwProtocol;
// ALG_ID aiCipher;
// DWORD dwCipherStrength;
// ALG_ID aiHash;
// DWORD dwHashStrength;
// ALG_ID aiExch;
// DWORD dwExchStrength;
// } SecPkgContext_ConnectionInfo;
//
//--------------------------------------------------------------------------
SECURITY_STATUS
SpQueryConnectionInfo(
PSPContext pContext,
SecPkgContext_ConnectionInfo *pConnectionInfo)
{
DebugLog((DEB_TRACE, "QueryContextAttributes(SECPKG_ATTR_CONNECTION_INFO)\n"));
if (NULL == pContext->pCipherInfo ||
NULL == pContext->pHashInfo ||
NULL == pContext->pKeyExchInfo)
{
return SP_LOG_RESULT(SEC_E_UNSUPPORTED_FUNCTION);
}
ZeroMemory(pConnectionInfo, sizeof(SecPkgContext_ConnectionInfo));
pConnectionInfo->dwProtocol = pContext->RipeZombie->fProtocol;
if(pContext->pCipherInfo->aiCipher != CALG_NULLCIPHER)
{
pConnectionInfo->aiCipher = pContext->pCipherInfo->aiCipher;
pConnectionInfo->dwCipherStrength = pContext->pCipherInfo->dwStrength;
}
pConnectionInfo->aiHash = pContext->pHashInfo->aiHash;
pConnectionInfo->dwHashStrength = pContext->pHashInfo->cbCheckSum * 8;
pConnectionInfo->aiExch = pContext->pKeyExchInfo->aiExch;
pConnectionInfo->dwExchStrength = pContext->RipeZombie->dwExchStrength;
return SEC_E_OK;
}
//+-------------------------------------------------------------------------
//
// Function: SpQueryIssuerList
//
// Synopsis: Retrieves the SECPKG_ATTR_ISSUER_LIST context attribute.
//
// Arguments:
//
// Returns:
//
// Notes: The buffer returned contains the following structure:
//
// typedef struct _SecPkgContext_IssuerListInfo
// {
// DWORD cbIssuerList;
// PBYTE pIssuerList;
// } SecPkgContext_IssuerListInfo;
//
//--------------------------------------------------------------------------
SECURITY_STATUS
SpQueryIssuerList(
LSA_SEC_HANDLE ContextHandle,
PVOID Buffer)
{
SecPkgContext_IssuerListInfo IssuerList;
DWORD Size;
PSPContext pContext;
SECURITY_STATUS Status;
PVOID pvClient = NULL;
DebugLog((DEB_TRACE, "QueryContextAttributes(SECPKG_ATTR_ISSUER_LIST)\n"));
pContext = (PSPContext)ContextHandle;
Size = sizeof( SecPkgContext_IssuerListInfo );
//
// Obtain data from Schannel.
//
// The issuer list is returned in the SSL3 wire format, which
// consists of a bunch of issuer names, each prepended
// with a two byte size (in big endian). Additionally, the list
// is also prepended with a two byte list size (also in big
// endian).
IssuerList.cbIssuerList = pContext->cbIssuerList;
IssuerList.pIssuerList = pContext->pbIssuerList;
//
// Copy buffers to client memory.
//
if(IssuerList.cbIssuerList && IssuerList.pIssuerList)
{
Status = LsaTable->AllocateClientBuffer(
NULL,
IssuerList.cbIssuerList,
&pvClient);
if(FAILED(Status))
{
return SP_LOG_RESULT(Status);
}
Status = LsaTable->CopyToClientBuffer(
NULL,
IssuerList.cbIssuerList,
pvClient,
IssuerList.pIssuerList);
if(FAILED(Status))
{
LsaTable->FreeClientBuffer(NULL, pvClient);
return SP_LOG_RESULT(Status);
}
IssuerList.pIssuerList = pvClient;
}
//
// Copy structure back to client memory.
//
Status = LsaTable->CopyToClientBuffer( NULL,
Size,
Buffer,
&IssuerList );
if(FAILED(Status))
{
LsaTable->FreeClientBuffer(NULL, pvClient);
return SP_LOG_RESULT(Status);
}
return SEC_E_OK;
}
//+-------------------------------------------------------------------------
//
// Function: SpQueryIssuerListEx
//
// Synopsis: Retrieves the SECPKG_ATTR_ISSUER_LIST_EX context attribute.
//
// Arguments:
//
// Returns:
//
// Notes: The buffer returned contains the following structure:
//
// typedef struct _SecPkgContext_IssuerListInfoEx
// {
// PCERT_NAME_BLOB aIssuers;
// DWORD cIssuers;
// } SecPkgContext_IssuerListInfoEx;
//
//--------------------------------------------------------------------------
SECURITY_STATUS
SpQueryIssuerListEx(
LSA_SEC_HANDLE ContextHandle,
PVOID Buffer)
{
SecPkgContext_IssuerListInfoEx IssuerListEx;
DWORD Size;
PSPContext pContext;
SECURITY_STATUS Status;
PVOID pvClient = NULL;
DWORD cIssuers;
PBYTE pbIssuerList;
DWORD cbIssuerList;
PBYTE pbIssuer;
DWORD cbIssuer;
PBYTE pbClientIssuer;
PCERT_NAME_BLOB paIssuerBlobs;
DWORD cbIssuerBlobs;
DWORD i;
DebugLog((DEB_TRACE, "QueryContextAttributes(SECPKG_ATTR_ISSUER_LIST_EX)\n"));
pContext = (PSPContext)ContextHandle;
Size = sizeof( SecPkgContext_IssuerListInfoEx );
//
// Obtain data from Schannel.
//
IssuerListEx.cIssuers = 0;
IssuerListEx.aIssuers = NULL;
if(pContext->pbIssuerList && pContext->cbIssuerList > 2)
{
pbIssuerList = pContext->pbIssuerList + 2;
cbIssuerList = pContext->cbIssuerList - 2;
// Count issuers.
cIssuers = 0;
pbIssuer = pbIssuerList;
while(pbIssuer + 1 < pbIssuerList + cbIssuerList)
{
cbIssuer = COMBINEBYTES(pbIssuer[0], pbIssuer[1]);
pbIssuer += 2 + cbIssuer;
cIssuers++;
}
// Allocate memory for list of blobs.
cbIssuerBlobs = cIssuers * sizeof(CERT_NAME_BLOB);
paIssuerBlobs = SPExternalAlloc(cbIssuerBlobs);
if(paIssuerBlobs == NULL)
{
return SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
}
// Allocate memory for issuer list.
Status = LsaTable->AllocateClientBuffer(
NULL,
cbIssuerBlobs + cbIssuerList,
&pvClient);
if(FAILED(Status))
{
SPExternalFree(paIssuerBlobs);
return SP_LOG_RESULT(Status);
}
// Copy the raw issuer list into client memory.
Status = LsaTable->CopyToClientBuffer(
NULL,
cbIssuerList,
(PBYTE)pvClient + cbIssuerBlobs,
pbIssuerList );
if(FAILED(Status))
{
SPExternalFree(paIssuerBlobs);
LsaTable->FreeClientBuffer(NULL, pvClient);
return SP_LOG_RESULT(Status);
}
// Build the issuer blob list.
pbIssuer = pbIssuerList;
pbClientIssuer = (PBYTE)pvClient + cbIssuerBlobs;
for(i = 0; i < cIssuers; i++)
{
paIssuerBlobs[i].pbData = pbClientIssuer + 2;
paIssuerBlobs[i].cbData = COMBINEBYTES(pbIssuer[0], pbIssuer[1]);
pbIssuer += 2 + paIssuerBlobs[i].cbData;
pbClientIssuer += 2 + paIssuerBlobs[i].cbData;
}
// Copy the blob list into client memory.
Status = LsaTable->CopyToClientBuffer(
NULL,
cbIssuerBlobs,
pvClient,
paIssuerBlobs );
if(FAILED(Status))
{
SPExternalFree(paIssuerBlobs);
LsaTable->FreeClientBuffer(NULL, pvClient);
return SP_LOG_RESULT(Status);
}
SPExternalFree(paIssuerBlobs);
IssuerListEx.cIssuers = cIssuers;
IssuerListEx.aIssuers = pvClient;
}
//
// Copy structure back to client memory.
//
Status = LsaTable->CopyToClientBuffer( NULL,
Size,
Buffer,
&IssuerListEx );
if(FAILED(Status))
{
if(pvClient) LsaTable->FreeClientBuffer(NULL, pvClient);
return SP_LOG_RESULT(Status);
}
return SEC_E_OK;
}
//+-------------------------------------------------------------------------
//
// Function: SpQueryKeyInfo
//
// Synopsis: Retrieves the SECPKG_ATTR_KEY_INFO context attribute.
//
// Arguments:
//
// Returns:
//
// Notes: The buffer returned contains the following structure:
//
// typedef struct _SecPkgContext_KeyInfoW
// {
// SEC_WCHAR SEC_FAR * sSignatureAlgorithmName;
// SEC_WCHAR SEC_FAR * sEncryptAlgorithmName;
// unsigned long KeySize;
// unsigned long SignatureAlgorithm;
// unsigned long EncryptAlgorithm;
// } SecPkgContext_KeyInfoW;
//
//--------------------------------------------------------------------------
SECURITY_STATUS
SpQueryKeyInfo(
PSPContext pContext,
PVOID Buffer)
{
SecPkgContext_KeyInfo *pKeyInfo;
DWORD cchSigName;
DWORD cbSigName;
DWORD cchCipherName;
DWORD cbCipherName;
UNICODE_STRING UniString;
ANSI_STRING AnsiString;
NTSTATUS Status;
DebugLog((DEB_TRACE, "QueryContextAttributes(SECPKG_ATTR_KEY_INFO)\n"));
if (NULL == pContext->pCipherInfo ||
NULL == pContext->pHashInfo ||
NULL == pContext->pKeyExchInfo)
{
return SP_LOG_RESULT(SEC_E_UNSUPPORTED_FUNCTION);
}
if (NULL == pContext->pCipherInfo->szName)
{
return SP_LOG_RESULT(SEC_E_INTERNAL_ERROR);
}
pKeyInfo = (SecPkgContext_KeyInfo *)Buffer;
ZeroMemory(pKeyInfo, sizeof(*pKeyInfo));
pKeyInfo->KeySize = pContext->pCipherInfo->dwStrength;
pKeyInfo->EncryptAlgorithm = pContext->pCipherInfo->aiCipher;
pKeyInfo->SignatureAlgorithm = 0;
cchSigName = lstrlenA(pContext->pKeyExchInfo->szName);
cbSigName = (cchSigName + 1) * sizeof(WCHAR);
pKeyInfo->sSignatureAlgorithmName = LocalAlloc(LPTR, cbSigName);
if(pKeyInfo->sSignatureAlgorithmName == NULL)
{
Status = SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
goto done;
}
RtlInitAnsiString(&AnsiString,
pContext->pKeyExchInfo->szName);
UniString.Length = 0;
UniString.MaximumLength = (USHORT)cbSigName;
UniString.Buffer = pKeyInfo->sSignatureAlgorithmName;
RtlAnsiStringToUnicodeString(&UniString,
&AnsiString,
FALSE);
cchCipherName = lstrlenA(pContext->pCipherInfo->szName);
cbCipherName = (cchCipherName + 1) * sizeof(WCHAR);
pKeyInfo->sEncryptAlgorithmName = LocalAlloc(LPTR, cbCipherName);
if(pKeyInfo->sEncryptAlgorithmName == NULL)
{
Status = SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
goto done;
}
RtlInitAnsiString(&AnsiString,
pContext->pCipherInfo->szName);
UniString.Length = 0;
UniString.MaximumLength = (USHORT)cbCipherName;
UniString.Buffer = pKeyInfo->sEncryptAlgorithmName;
RtlAnsiStringToUnicodeString(&UniString,
&AnsiString,
FALSE);
Status = PCT_ERR_OK;
done:
if(Status != PCT_ERR_OK)
{
if(pKeyInfo->sSignatureAlgorithmName)
{
LocalFree(pKeyInfo->sSignatureAlgorithmName);
pKeyInfo->sSignatureAlgorithmName = NULL;
}
if(pKeyInfo->sEncryptAlgorithmName)
{
LocalFree(pKeyInfo->sEncryptAlgorithmName);
pKeyInfo->sEncryptAlgorithmName = NULL;
}
}
return Status;
}
//+-------------------------------------------------------------------------
//
// Function: SpQueryLifespan
//
// Synopsis: Retrieves the SECPKG_ATTR_LIFESPAN context attribute.
//
// Arguments:
//
// Returns:
//
// Notes: The buffer returned contains the following structure:
//
// typedef struct _SecPkgContext_Lifespan
// {
// TimeStamp tsStart;
// TimeStamp tsExpiry;
// } SecPkgContext_Lifespan;
//
//--------------------------------------------------------------------------
SECURITY_STATUS
SpQueryLifespan(
PSPContext pContext,
SecPkgContext_Lifespan *pLifespan)
{
PCCERT_CONTEXT pCertContext;
NTSTATUS Status;
DebugLog((DEB_TRACE, "QueryContextAttributes(SECPKG_ATTR_LIFESPAN)\n"));
if(pContext->RipeZombie->pbServerCertificate)
{
Status = DeserializeCertContext(&pCertContext,
pContext->RipeZombie->pbServerCertificate,
pContext->RipeZombie->cbServerCertificate);
if(Status != PCT_ERR_OK)
{
SP_LOG_RESULT(Status);
return SEC_E_INSUFFICIENT_MEMORY;
}
pLifespan->tsStart.QuadPart = *((LONGLONG *)&pCertContext->pCertInfo->NotBefore);
pLifespan->tsExpiry.QuadPart = *((LONGLONG *)&pCertContext->pCertInfo->NotAfter);
CertFreeCertificateContext(pCertContext);
}
else
{
pLifespan->tsStart.QuadPart = 0;
pLifespan->tsExpiry.QuadPart = MAXTIMEQUADPART;
}
return SEC_E_OK;
}
//+-------------------------------------------------------------------------
//
// Function: SpQueryLocalCertContext
//
// Synopsis: Retrieves the SECPKG_ATTR_LOCAL_CERT_CONTEXT
// context attribute.
//
// Arguments:
//
// Returns:
//
// Notes: The buffer returned contains a pointer to a CERT_CONTEXT
// structure.
//
//--------------------------------------------------------------------------
SECURITY_STATUS
SpQueryLocalCertContext(
LSA_SEC_HANDLE ContextHandle,
PVOID Buffer)
{
DWORD Size;
PSPContext pContext;
SECURITY_STATUS Status;
PCCERT_CONTEXT pCertContext = NULL;
SecBuffer Input;
SecBuffer Output;
DebugLog((DEB_TRACE, "QueryContextAttributes(SECPKG_ATTR_LOCAL_CERT_CONTEXT)\n"));
pContext = (PSPContext)ContextHandle;
Size = sizeof( PCCERT_CONTEXT );
//
// Obtain data from Schannel.
//
if(pContext->dwProtocol & SP_PROT_CLIENTS)
{
pCertContext = pContext->RipeZombie->pClientCert;
}
else
{
pCertContext = pContext->RipeZombie->pActiveServerCred->pCert;
}
//
// Copy buffers to client memory.
//
if(pCertContext)
{
// Serialize the certificate context, as well as the associated
// certificate store.
Status = SerializeCertContext(pCertContext,
NULL,
&Input.cbBuffer);
if(FAILED(Status))
{
return SP_LOG_RESULT(Status);
}
SafeAllocaAllocate(Input.pvBuffer, Input.cbBuffer);
if(Input.pvBuffer == NULL)
{
return SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
}
Status = SerializeCertContext(pCertContext,
Input.pvBuffer,
&Input.cbBuffer);
if(FAILED(Status))
{
SafeAllocaFree(Input.pvBuffer);
return SP_LOG_RESULT(Status);
}
// Call back into the user process in order to replicate the
// certificate context and store over there.
Input.BufferType = SECBUFFER_DATA;
Status = PerformApplicationCallback(SCH_DOWNLOAD_CERT_CALLBACK,
0,
0,
&Input,
&Output,
TRUE);
SafeAllocaFree(Input.pvBuffer);
if(FAILED(Status))
{
return SP_LOG_RESULT(Status);
}
pCertContext = *(PCCERT_CONTEXT *)(Output.pvBuffer);
SPExternalFree(Output.pvBuffer);
}
//
// Copy structure back to client memory.
//
if(pCertContext)
{
Status = LsaTable->CopyToClientBuffer( NULL,
Size,
Buffer,
(PVOID)&pCertContext );
if(FAILED(Status))
{
return SP_LOG_RESULT(Status);
}
}
else
{
return SP_LOG_RESULT(SEC_E_NO_CREDENTIALS);
}
return SEC_E_OK;
}
//+-------------------------------------------------------------------------
//
// Function: SpQueryRemoteCertContext
//
// Synopsis: Retrieves the SECPKG_ATTR_REMOTE_CERT_CONTEXT
// context attribute.
//
// Arguments:
//
// Returns:
//
// Notes: The buffer returned contains a pointer to a CERT_CONTEXT
// structure.
//
//--------------------------------------------------------------------------
SECURITY_STATUS
SpQueryRemoteCertContext(
PSPContext pContext,
PVOID Buffer)
{
PCCERT_CONTEXT pCertContext;
SP_STATUS pctRet;
DebugLog((DEB_TRACE, "QueryContextAttributes(SECPKG_ATTR_REMOTE_CERT_CONTEXT)\n"));
if(pContext->RipeZombie->pbServerCertificate)
{
pctRet = DeserializeCertContext(&pCertContext,
pContext->RipeZombie->pbServerCertificate,
pContext->RipeZombie->cbServerCertificate);
if(pctRet != PCT_ERR_OK)
{
return SP_LOG_RESULT(pctRet);
}
*(PCCERT_CONTEXT *)Buffer = pCertContext;
return SEC_E_OK;
}
else
{
return SP_LOG_RESULT(SEC_E_NO_CREDENTIALS);
}
}
//+-------------------------------------------------------------------------
//
// Function: SpQueryLocalCred
//
// Synopsis: Retrieves the SECPKG_ATTR_LOCAL_CRED context attribute.
//
// Arguments:
//
// Returns:
//
// Notes: The buffer returned contains the following structure:
//
// typedef struct _SecPkgContext_LocalCredentialInfo
// {
// DWORD cbCertificateChain;
// PBYTE pbCertificateChain;
// DWORD cCertificates;
// DWORD fFlags;
// DWORD dwBits;
// } SecPkgContext_LocalCredentialInfo;
//
//--------------------------------------------------------------------------
SECURITY_STATUS
SpQueryLocalCred(
LSA_SEC_HANDLE ContextHandle,
PVOID Buffer)
{
SecPkgContext_LocalCredentialInfo CredInfo;
DWORD Size;
PSPContext pContext;
SECURITY_STATUS Status;
PVOID pvClient = NULL;
PCCERT_CONTEXT pCert = NULL;
PUBLICKEY * pKey = NULL;
RSAPUBKEY * pk = NULL;
PSPCredential pCred;
DebugLog((DEB_TRACE, "QueryContextAttributes(SECPKG_ATTR_LOCAL_CRED)\n"));
pContext = (PSPContext)ContextHandle;
Size = sizeof( SecPkgContext_LocalCredentialInfo );
//
// Obtain data from Schannel.
//
ZeroMemory(&CredInfo, Size);
if(pContext->dwProtocol & SP_PROT_CLIENTS)
{
pCred = pContext->pActiveClientCred;
}
else
{
pCred = pContext->RipeZombie->pActiveServerCred;
}
if(pCred)
{
pCert = pCred->pCert;
pKey = pCred->pPublicKey;
}
if(pCert)
{
CredInfo.fFlags |= LCRED_CRED_EXISTS;
CredInfo.pbCertificateChain = pCert->pbCertEncoded;
CredInfo.cbCertificateChain = pCert->cbCertEncoded;
CredInfo.cCertificates = 1;
// Compute number of bits in the certificate's public key.
CredInfo.dwBits = 0;
pk = (RSAPUBKEY *)((pKey->pPublic) + 1);
if(pk)
{
CredInfo.dwBits = pk->bitlen;
}
}
//
// Copy buffers to client memory.
//
if(CredInfo.pbCertificateChain)
{
Status = LsaTable->AllocateClientBuffer(
NULL,
CredInfo.cbCertificateChain,
&pvClient);
if(FAILED(Status))
{
return SP_LOG_RESULT(Status);
}
Status = LsaTable->CopyToClientBuffer(
NULL,
CredInfo.cbCertificateChain,
pvClient,
CredInfo.pbCertificateChain);
if(FAILED(Status))
{
LsaTable->FreeClientBuffer(NULL, pvClient);
return SP_LOG_RESULT(Status);
}
CredInfo.pbCertificateChain = pvClient;
}
//
// Copy structure back to client memory.
//
Status = LsaTable->CopyToClientBuffer( NULL,
Size,
Buffer,
&CredInfo );
if(FAILED(Status))
{
LsaTable->FreeClientBuffer(NULL, pvClient);
return SP_LOG_RESULT(Status);
}
return SEC_E_OK;
}
//+-------------------------------------------------------------------------
//
// Function: SpQueryRemoteCred
//
// Synopsis: Retrieves the SECPKG_ATTR_REMOTE_CRED context attribute.
//
// Arguments:
//
// Returns:
//
// Notes: The buffer returned contains the following structure:
//
// typedef struct _SecPkgContext_LocalCredentialInfo
// {
// DWORD cbCertificateChain;
// PBYTE pbCertificateChain;
// DWORD cCertificates;
// DWORD fFlags;
// DWORD dwBits;
// } SecPkgContext_LocalCredentialInfo;
//
//--------------------------------------------------------------------------
SECURITY_STATUS
SpQueryRemoteCred(
PSPContext pContext,
PVOID Buffer)
{
SecPkgContext_LocalCredentialInfo *pCredInfo;
PCCERT_CONTEXT pCertContext = NULL;
PUBLICKEY * pKey = NULL;
RSAPUBKEY * pk = NULL;
SP_STATUS pctRet;
PBYTE pbCert;
DebugLog((DEB_TRACE, "QueryContextAttributes(SECPKG_ATTR_REMOTE_CRED)\n"));
pCredInfo = (SecPkgContext_LocalCredentialInfo *)Buffer;
ZeroMemory(pCredInfo, sizeof(*pCredInfo));
if(pContext->RipeZombie->pbServerCertificate)
{
pctRet = DeserializeCertContext(&pCertContext,
pContext->RipeZombie->pbServerCertificate,
pContext->RipeZombie->cbServerCertificate);
if(pctRet != PCT_ERR_OK)
{
return SP_LOG_RESULT(pctRet);
}
}
if(pCertContext)
{
pbCert = LocalAlloc(LPTR, pCertContext->cbCertEncoded);
if(pbCert == NULL)
{
return SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
}
memcpy(pbCert, pCertContext->pbCertEncoded, pCertContext->cbCertEncoded);
pCredInfo->fFlags |= LCRED_CRED_EXISTS;
pCredInfo->pbCertificateChain = pbCert;
pCredInfo->cbCertificateChain = pCertContext->cbCertEncoded;
pCredInfo->cCertificates = 1;
pCredInfo->dwBits = 0;
// Compute number of bits in the certificate's public key.
pctRet = SPPublicKeyFromCert(pCertContext, &pKey, NULL);
if(pctRet == PCT_ERR_OK)
{
pk = (RSAPUBKEY *)((pKey->pPublic) + 1);
if(pk)
{
pCredInfo->dwBits = pk->bitlen;
}
SPExternalFree(pKey);
}
CertFreeCertificateContext(pCertContext);
}
return SEC_E_OK;
}
//+-------------------------------------------------------------------------
//
// Function: SpQueryNames
//
// Synopsis: Retrieves the SECPKG_ATTR_NAMES context attribute.
//
// Arguments:
//
// Returns:
//
// Notes: The buffer returned contains the following structure:
//
// typedef struct _SecPkgContext_NamesW
// {
// SEC_WCHAR SEC_FAR * sUserName;
// } SecPkgContext_NamesW;
//
//--------------------------------------------------------------------------
SECURITY_STATUS
SpQueryNames(
PSPContext pContext,
SecPkgContext_Names *pNames)
{
SECURITY_STATUS Status;
PCCERT_CONTEXT pCert = NULL;
DWORD cchSubject;
DWORD cbSubject;
DebugLog((DEB_TRACE, "QueryContextAttributes(SECPKG_ATTR_NAMES)\n"));
//
// Obtain data from Schannel.
//
if(pContext->RipeZombie->pbServerCertificate == NULL)
{
return SP_LOG_RESULT(SEC_E_UNSUPPORTED_FUNCTION);
}
Status = DeserializeCertContext(&pCert,
pContext->RipeZombie->pbServerCertificate,
pContext->RipeZombie->cbServerCertificate);
if(Status != PCT_ERR_OK)
{
return SP_LOG_RESULT(Status);
}
//
// Build name string.
//
if(0 >= (cchSubject = CertNameToStr(pCert->dwCertEncodingType,
&pCert->pCertInfo->Subject,
CERT_X500_NAME_STR | CERT_NAME_STR_NO_PLUS_FLAG,
NULL,
0)))
{
CertFreeCertificateContext(pCert);
return SP_LOG_RESULT(SEC_E_UNSUPPORTED_FUNCTION);
}
cbSubject = (cchSubject + 1) * sizeof(TCHAR);
pNames->sUserName = LocalAlloc(LPTR, cbSubject);
if(pNames->sUserName == NULL)
{
CertFreeCertificateContext(pCert);
return SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
}
if(0 >= CertNameToStr(pCert->dwCertEncodingType,
&pCert->pCertInfo->Subject,
CERT_X500_NAME_STR | CERT_NAME_STR_NO_PLUS_FLAG,
pNames->sUserName,
cchSubject))
{
CertFreeCertificateContext(pCert);
LocalFree(pNames->sUserName);
return SP_LOG_RESULT(SEC_E_UNSUPPORTED_FUNCTION);
}
CertFreeCertificateContext(pCert);
return SEC_E_OK;
}
//+-------------------------------------------------------------------------
//
// Function: SpQueryPackageInfo
//
// Synopsis: Retrieves the SECPKG_ATTR_PACKAGE_INFO context attribute.
//
// Arguments:
//
// Returns:
//
// Notes: The buffer returned contains the following structure:
//
// typedef struct _SecPkgContext_PackageInfoW
// {
// PSecPkgInfoW PackageInfo;
// } SecPkgContext_PackageInfoW, SEC_FAR * PSecPkgContext_PackageInfoW;
//
//--------------------------------------------------------------------------
SECURITY_STATUS
SpQueryPackageInfo(
PSPContext pContext,
PVOID Buffer)
{
PSecPkgContext_PackageInfoW pPackageInfo;
SecPkgInfoW Info;
DWORD cbName;
DWORD cbComment;
UNREFERENCED_PARAMETER(pContext);
DebugLog((DEB_TRACE, "QueryContextAttributes(SECPKG_ATTR_PACKAGE_INFO)\n"));
SpSslGetInfo(&Info);
pPackageInfo = (PSecPkgContext_PackageInfoW)Buffer;
cbName = (lstrlen(Info.Name) + 1) * sizeof(WCHAR);
cbComment = (lstrlen(Info.Comment) + 1) * sizeof(WCHAR);
pPackageInfo->PackageInfo = LocalAlloc(LPTR, sizeof(SecPkgInfo) + cbName + cbComment);
if(pPackageInfo->PackageInfo == NULL)
{
return SP_LOG_RESULT(STATUS_INSUFFICIENT_RESOURCES);
}
pPackageInfo->PackageInfo->wVersion = Info.wVersion;
pPackageInfo->PackageInfo->wRPCID = Info.wRPCID;
pPackageInfo->PackageInfo->fCapabilities = Info.fCapabilities;
pPackageInfo->PackageInfo->cbMaxToken = Info.cbMaxToken;
pPackageInfo->PackageInfo->Name = (LPWSTR)(pPackageInfo->PackageInfo + 1);
pPackageInfo->PackageInfo->Comment = (LPWSTR)((PBYTE)pPackageInfo->PackageInfo->Name + cbName);
lstrcpy(
pPackageInfo->PackageInfo->Name,
Info.Name);
lstrcpy(
pPackageInfo->PackageInfo->Comment,
Info.Comment);
return SEC_E_OK;
}
//+-------------------------------------------------------------------------
//
// Function: SpQueryProtoInfo
//
// Synopsis: Retrieves the SECPKG_ATTR_PROTO_INFO context attribute.
//
// Arguments:
//
// Returns:
//
// Notes: The buffer returned contains the following structure:
//
// typedef struct _SecPkgContext_ProtoInfoW
// {
// SEC_WCHAR SEC_FAR * sProtocolName;
// unsigned long majorVersion;
// unsigned long minorVersion;
// } SecPkgContext_ProtoInfoW;
//
//--------------------------------------------------------------------------
SECURITY_STATUS
SpQueryProtoInfo(
PSPContext pContext,
PVOID Buffer)
{
SecPkgContext_ProtoInfo *pProtoInfo;
DWORD index;
DWORD cbName;
DebugLog((DEB_TRACE, "QueryContextAttributes(SECPKG_ATTR_PROTO_INFO)\n"));
pProtoInfo = (SecPkgContext_ProtoInfo *)Buffer;
for(index = 0;
index < sizeof(rgProts) / sizeof(PROTO_ID);
index += 1)
{
if(pContext->RipeZombie->fProtocol == rgProts[index].dwProtoId)
{
break;
}
}
if(index >= sizeof(rgProts) / sizeof(PROTO_ID))
{
return SP_LOG_RESULT(SEC_E_UNSUPPORTED_FUNCTION);
}
cbName = (lstrlen(rgProts[index].szProto) + 1) * sizeof(WCHAR);
pProtoInfo->sProtocolName = LocalAlloc(LPTR, cbName);
if(pProtoInfo->sProtocolName == NULL)
{
return SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
}
lstrcpy(pProtoInfo->sProtocolName, rgProts[index].szProto);
pProtoInfo->majorVersion = rgProts[index].dwMajor;
pProtoInfo->minorVersion = rgProts[index].dwMinor;
return SEC_E_OK;
}
//+-------------------------------------------------------------------------
//
// Function: SpQuerySizes
//
// Synopsis: Retrieves the SECPKG_ATTR_SIZES context attribute.
//
// Arguments:
//
// Returns:
//
// Notes: The buffer returned contains the following structure:
//
// typedef struct _SecPkgContext_Sizes
// {
// unsigned long cbMaxToken;
// unsigned long cbMaxSignature;
// unsigned long cbBlockSize;
// unsigned long cbSecurityTrailer;
// } SecPkgContext_Sizes;
//
//--------------------------------------------------------------------------
SECURITY_STATUS
SpQuerySizes(
PSPContext pContext,
SecPkgContext_Sizes *pSizes)
{
DebugLog((DEB_TRACE, "QueryContextAttributes(SECPKG_ATTR_SIZES)\n"));
if (NULL == pContext->pCipherInfo ||
NULL == pContext->pHashInfo)
{
return SP_LOG_RESULT(SEC_E_INVALID_HANDLE);
}
switch(pContext->RipeZombie->fProtocol)
{
case SP_PROT_SSL2_CLIENT:
case SP_PROT_SSL2_SERVER:
pSizes->cbMaxToken = SSL2_MAX_MESSAGE_LENGTH;
pSizes->cbSecurityTrailer = 2 + pContext->pHashInfo->cbCheckSum;
if(pContext->pCipherInfo->dwBlockSize > 1)
{
pSizes->cbSecurityTrailer += 1 + pContext->pCipherInfo->dwBlockSize; // 3 byte header
}
break;
case SP_PROT_PCT1_CLIENT:
case SP_PROT_PCT1_SERVER:
pSizes->cbMaxToken = PCT1_MAX_MESSAGE_LENGTH;
pSizes->cbSecurityTrailer = 2 + pContext->pHashInfo->cbCheckSum;
if(pContext->pCipherInfo->dwBlockSize > 1)
{
pSizes->cbSecurityTrailer += 1 + pContext->pCipherInfo->dwBlockSize; // 3 byte header
}
break;
case SP_PROT_SSL3_CLIENT:
case SP_PROT_SSL3_SERVER:
case SP_PROT_TLS1_CLIENT:
case SP_PROT_TLS1_SERVER:
pSizes->cbMaxToken = SSL3_MAX_MESSAGE_LENGTH;
pSizes->cbSecurityTrailer = 5 + pContext->pHashInfo->cbCheckSum;
if(pContext->pCipherInfo->dwBlockSize > 1)
{
pSizes->cbSecurityTrailer += pContext->pCipherInfo->dwBlockSize;
}
break;
default:
pSizes->cbMaxToken = SSL3_MAX_MESSAGE_LENGTH;
pSizes->cbSecurityTrailer = 0;
}
pSizes->cbMaxSignature = pContext->pHashInfo->cbCheckSum;
pSizes->cbBlockSize = pContext->pCipherInfo->dwBlockSize;
return SEC_E_OK;
}
//+-------------------------------------------------------------------------
//
// Function: SpQueryStreamSizes
//
// Synopsis: Retrieves the SECPKG_ATTR_STREAM_SIZES context attribute.
//
// Arguments:
//
// Returns:
//
// Notes: The buffer returned contains the following structure:
//
// typedef struct _SecPkgContext_StreamSizes
// {
// unsigned long cbHeader;
// unsigned long cbTrailer;
// unsigned long cbMaximumMessage;
// unsigned long cBuffers;
// unsigned long cbBlockSize;
// } SecPkgContext_StreamSizes;
//
//--------------------------------------------------------------------------
SECURITY_STATUS
SpQueryStreamSizes(
PSPContext pContext,
SecPkgContext_StreamSizes *pStreamSizes)
{
DebugLog((DEB_TRACE, "QueryContextAttributes(SECPKG_ATTR_STREAM_SIZES)\n"));
if (NULL == pContext->pCipherInfo ||
NULL == pContext->pHashInfo)
{
return SP_LOG_RESULT(SEC_E_INVALID_HANDLE);
}
switch(pContext->RipeZombie->fProtocol)
{
case SP_PROT_SSL2_CLIENT:
case SP_PROT_SSL2_SERVER:
pStreamSizes->cbMaximumMessage = SSL2_MAX_MESSAGE_LENGTH;
pStreamSizes->cbHeader = 2 + pContext->pHashInfo->cbCheckSum;
pStreamSizes->cbTrailer = 0;
if(pContext->pCipherInfo->dwBlockSize > 1)
{
pStreamSizes->cbHeader += 1; // 3 byte header
pStreamSizes->cbTrailer += pContext->pCipherInfo->dwBlockSize;
}
break;
case SP_PROT_PCT1_CLIENT:
case SP_PROT_PCT1_SERVER:
pStreamSizes->cbMaximumMessage = PCT1_MAX_MESSAGE_LENGTH;
pStreamSizes->cbHeader = 2;
pStreamSizes->cbTrailer = pContext->pHashInfo->cbCheckSum;
if(pContext->pCipherInfo->dwBlockSize > 1)
{
pStreamSizes->cbHeader += 1; // 3 byte header
pStreamSizes->cbTrailer += pContext->pCipherInfo->dwBlockSize;
}
break;
case SP_PROT_TLS1_CLIENT:
case SP_PROT_TLS1_SERVER:
case SP_PROT_SSL3_CLIENT:
case SP_PROT_SSL3_SERVER:
pStreamSizes->cbMaximumMessage = SSL3_MAX_MESSAGE_LENGTH;
pStreamSizes->cbHeader = 5;
pStreamSizes->cbTrailer = pContext->pHashInfo->cbCheckSum;
if(pContext->pCipherInfo->dwBlockSize > 1)
{
pStreamSizes->cbTrailer += pContext->pCipherInfo->dwBlockSize;
}
break;
default:
pStreamSizes->cbMaximumMessage = SSL3_MAX_MESSAGE_LENGTH;
pStreamSizes->cbHeader = 0;
pStreamSizes->cbTrailer = 0;
}
pStreamSizes->cbBlockSize = pContext->pCipherInfo->dwBlockSize;
pStreamSizes->cBuffers = 4;
return SEC_E_OK;
}
//+-------------------------------------------------------------------------
//
// Function: SpQueryEapKeyBlock
//
// Synopsis: Retrieves the SECPKG_ATTR_EAP_KEY_BLOCK context attribute.
//
// Arguments:
//
// Returns:
//
// Notes: The buffer returned contains the following structure:
//
// typedef struct _SecPkgContext_EapKeyBlock
// {
// BYTE rgbKeys[128];
// BYTE rgbIVs[64];
// } SecPkgContext_EapKeyBlock, *PSecPkgContext_EapKeyBlock;
//
//--------------------------------------------------------------------------
SECURITY_STATUS
SpQueryEapKeyBlock(
LSA_SEC_HANDLE ContextHandle,
PVOID Buffer)
{
SecPkgContext_EapKeyBlock KeyBlock;
DWORD Size;
PSPContext pContext;
SECURITY_STATUS Status;
HCRYPTHASH hHash;
CRYPT_DATA_BLOB Data;
UCHAR rgbRandom[CB_SSL3_RANDOM + CB_SSL3_RANDOM];
DWORD cbRandom;
DWORD cbData;
DebugLog((DEB_TRACE, "QueryContextAttributes(SECPKG_ATTR_EAP_KEY_BLOCK)\n"));
pContext = (PSPContext)ContextHandle;
Size = sizeof( SecPkgContext_EapKeyBlock );
//
// Obtain data from Schannel.
//
if(!(pContext->RipeZombie->fProtocol & SP_PROT_TLS1))
{
// This attribute is defined for TLS only.
return SP_LOG_RESULT(SEC_E_UNSUPPORTED_FUNCTION);
}
if(!pContext->RipeZombie->hMasterKey)
{
return SP_LOG_RESULT(SEC_E_INVALID_HANDLE);
}
// Build random buffer.
CopyMemory(rgbRandom, pContext->rgbS3CRandom, CB_SSL3_RANDOM);
CopyMemory(rgbRandom + CB_SSL3_RANDOM, pContext->rgbS3SRandom, CB_SSL3_RANDOM);
cbRandom = CB_SSL3_RANDOM + CB_SSL3_RANDOM;
// rgbKeys = PRF(master_secret, "client EAP encryption", client_random + server_random);
// Compute the PRF
if(!CryptCreateHash(pContext->RipeZombie->hMasterProv,
CALG_TLS1PRF,
pContext->RipeZombie->hMasterKey,
0,
&hHash))
{
SP_LOG_RESULT(GetLastError());
return SEC_E_INTERNAL_ERROR;
}
Data.pbData = (PBYTE)TLS1_LABEL_EAP_KEYS;
Data.cbData = CB_TLS1_LABEL_EAP_KEYS;
if(!CryptSetHashParam(hHash,
HP_TLS1PRF_LABEL,
(PBYTE)&Data,
0))
{
SP_LOG_RESULT(GetLastError());
CryptDestroyHash(hHash);
return SEC_E_INTERNAL_ERROR;
}
Data.pbData = rgbRandom;
Data.cbData = cbRandom;
if(!CryptSetHashParam(hHash,
HP_TLS1PRF_SEED,
(PBYTE)&Data,
0))
{
SP_LOG_RESULT(GetLastError());
CryptDestroyHash(hHash);
return SEC_E_INTERNAL_ERROR;
}
cbData = sizeof(KeyBlock.rgbKeys);
if(!CryptGetHashParam(hHash,
HP_HASHVAL,
KeyBlock.rgbKeys,
&cbData,
0))
{
SP_LOG_RESULT(GetLastError());
CryptDestroyHash(hHash);
return SEC_E_INTERNAL_ERROR;
}
SP_ASSERT(cbData == sizeof(KeyBlock.rgbKeys));
CryptDestroyHash(hHash);
// IVs = PRF("", "client EAP encryption", client_random + server_random)
if(!PRF(NULL, 0,
(PBYTE)TLS1_LABEL_EAP_KEYS, CB_TLS1_LABEL_EAP_KEYS,
rgbRandom, sizeof(rgbRandom),
KeyBlock.rgbIVs, sizeof(KeyBlock.rgbIVs)))
{
return SP_LOG_RESULT(SEC_E_INTERNAL_ERROR);
}
//
// Copy structure back to client memory.
//
Status = LsaTable->CopyToClientBuffer( NULL,
Size,
Buffer,
&KeyBlock );
if(FAILED(Status))
{
return SP_LOG_RESULT(Status);
}
return SEC_E_OK;
}
//+-------------------------------------------------------------------------
//
// Function: SpQueryApplicationData
//
// Synopsis: Retrieves the SECPKG_ATTR_APP_DATA context attribute.
//
// Arguments:
//
// Returns:
//
// Notes: The buffer returned contains the following structure:
//
// typedef struct _SecPkgContext_SessionAppData
// {
// DWORD dwFlags;
// DWORD cbAppData;
// PBYTE pbAppData;
// } SecPkgContext_SessionAppData, *PSecPkgContext_SessionAppData;
//
//--------------------------------------------------------------------------
SECURITY_STATUS
SpQueryApplicationData(
LSA_SEC_HANDLE ContextHandle,
PVOID Buffer)
{
SecPkgContext_SessionAppData AppData;
PBYTE pbAppData = NULL;
DWORD cbAppData = 0;
PSPContext pContext;
SECURITY_STATUS Status;
PVOID pvClient = NULL;
DebugLog((DEB_TRACE, "QueryContextAttributes(SECPKG_ATTR_APP_DATA)\n"));
pContext = (PSPContext)ContextHandle;
if(pContext == NULL || pContext->RipeZombie == NULL)
{
return SP_LOG_RESULT(SEC_E_INVALID_HANDLE);
}
//
// Get application data from cache.
//
Status = GetCacheAppData(pContext->RipeZombie, &pbAppData, &cbAppData);
if(FAILED(Status))
{
SP_LOG_RESULT(Status);
goto cleanup;
}
//
// Allocate memory for application data in application process.
//
if(pbAppData != NULL)
{
Status = LsaTable->AllocateClientBuffer(
NULL,
cbAppData,
&pvClient);
if(FAILED(Status))
{
SP_LOG_RESULT(Status);
goto cleanup;
}
Status = LsaTable->CopyToClientBuffer(
NULL,
cbAppData,
pvClient,
pbAppData);
if(FAILED(Status))
{
SP_LOG_RESULT(Status);
goto cleanup;
}
}
//
// Build output structure.
//
ZeroMemory(&AppData, sizeof(AppData));
AppData.cbAppData = cbAppData;
AppData.pbAppData = pvClient;
//
// Copy output structure back to client memory.
//
Status = LsaTable->CopyToClientBuffer( NULL,
sizeof(SecPkgContext_SessionAppData),
Buffer,
&AppData);
if(FAILED(Status))
{
SP_LOG_RESULT(Status);
goto cleanup;
}
// Operation has succeeded, so consume this buffer.
pvClient = NULL;
cleanup:
if(pvClient)
{
LsaTable->FreeClientBuffer(NULL, pvClient);
}
if(pbAppData)
{
SPExternalFree(pbAppData);
}
return Status;
}
//+-------------------------------------------------------------------------
//
// Function: SpQuerySessionInfo
//
// Synopsis: Retrieves the SECPKG_ATTR_SESSION_INFO context attribute.
//
// Arguments:
//
// Returns:
//
// Notes: The buffer returned contains the following structure:
//
// typedef struct _SecPkgContext_SessionInfo
// {
// DWORD dwFlags;
// DWORD cbSessionId;
// BYTE rgbSessionId[32];
// } SecPkgContext_SessionInfo, *PSecPkgContext_SessionInfo;
//
//--------------------------------------------------------------------------
SECURITY_STATUS
SpQuerySessionInfo(
PSPContext pContext,
SecPkgContext_SessionInfo *pSessionInfo)
{
DebugLog((DEB_TRACE, "QueryContextAttributes(SECPKG_ATTR_SESSION_INFO)\n"));
if (NULL == pContext->RipeZombie)
{
return SP_LOG_RESULT(SEC_E_INVALID_HANDLE);
}
ZeroMemory(pSessionInfo, sizeof(SecPkgContext_SessionInfo));
if(!(pContext->Flags & CONTEXT_FLAG_FULL_HANDSHAKE))
{
pSessionInfo->dwFlags = SSL_SESSION_RECONNECT;
}
pSessionInfo->cbSessionId = pContext->RipeZombie->cbSessionID;
memcpy(pSessionInfo->rgbSessionId, pContext->RipeZombie->SessionID, pContext->RipeZombie->cbSessionID);
return SEC_E_OK;
}
//+-------------------------------------------------------------------------
//
// Function: SpQueryContextAttributes
//
// Synopsis: Querys attributes of the specified context
//
// Effects:
//
// Arguments:
//
// Requires:
//
// Returns:
//
// Notes: The following attributes are supported by the Schannel
// package:
//
// SECPKG_ATTR_AUTHORITY
// SECPKG_ATTR_CONNECTION_INFO
// SECPKG_ATTR_ISSUER_LIST
// SECPKG_ATTR_ISSUER_LIST_EX
// SECPKG_ATTR_KEY_INFO
// SECPKG_ATTR_LIFESPAN
// SECPKG_ATTR_LOCAL_CERT_CONTEXT
// SECPKG_ATTR_LOCAL_CRED
// SECPKG_ATTR_NAMES
// SECPKG_ATTR_PROTO_INFO
// SECPKG_ATTR_REMOTE_CERT_CONTEXT
// SECPKG_ATTR_REMOTE_CRED
// SECPKG_ATTR_SIZES
// SECPKG_ATTR_STREAM_SIZES
//
//--------------------------------------------------------------------------
SECURITY_STATUS
SEC_ENTRY
SpLsaQueryContextAttributes(
LSA_SEC_HANDLE Context,
ULONG Attribute,
PVOID Buffer)
{
SECURITY_STATUS Status;
PSPContext pContext;
pContext = (PSPContext)Context;
switch(Attribute)
{
case SECPKG_ATTR_AUTHORITY :
Status = SpQueryAuthority(Context, Buffer);
break;
case SECPKG_ATTR_ISSUER_LIST :
Status = SpQueryIssuerList(Context, Buffer);
break;
case SECPKG_ATTR_ISSUER_LIST_EX:
Status = SpQueryIssuerListEx(Context, Buffer);
break;
// case SECPKG_ATTR_KEY_INFO :
// Status = SpQueryKeyInfo(Context, Buffer);
// break;
// case SECPKG_ATTR_LIFESPAN :
// Status = SpQueryLifespan(Context, Buffer);
// break;
case SECPKG_ATTR_LOCAL_CERT_CONTEXT:
Status = SpQueryLocalCertContext(Context, Buffer);
break;
case SECPKG_ATTR_LOCAL_CRED:
Status = SpQueryLocalCred(Context, Buffer);
break;
// case SECPKG_ATTR_NAMES :
// Status = SpQueryNames(Context, Buffer);
// break;
// case SECPKG_ATTR_PROTO_INFO:
// Status = SpQueryProtoInfo(Context, Buffer);
// break;
// case SECPKG_ATTR_REMOTE_CERT_CONTEXT:
// Status = SpQueryCertContext(Context, Buffer, FALSE);
// break;
// case SECPKG_ATTR_REMOTE_CRED:
// Status = SpQueryRemoteCred(Context, Buffer);
// break;
// case SECPKG_ATTR_SIZES:
// Status = SpQuerySizes(Context, Buffer);
// break;
// case SECPKG_ATTR_STREAM_SIZES:
// Status = SpQueryStreamSizes(Context, Buffer);
// break;
case SECPKG_ATTR_EAP_KEY_BLOCK:
Status = SpQueryEapKeyBlock(Context, Buffer);
break;
// case SECPKG_ATTR_MAPPED_CRED_ATTR:
// Status = SpQueryMappedCredAttr(Context, Buffer);
// break;
case SECPKG_ATTR_APP_DATA:
Status = SpQueryApplicationData(Context, Buffer);
break;
default:
DebugLog((DEB_ERROR, "QueryContextAttributes(unsupported function %d)\n", Attribute));
return SP_LOG_RESULT(SEC_E_UNSUPPORTED_FUNCTION);
}
return Status;
}
//+-------------------------------------------------------------------------
//
// Function: SpUserQueryContextAttributes
//
// Synopsis: User mode QueryContextAttribute.
//
// Effects:
//
// Arguments:
//
// Requires:
//
// Returns:
//
// Notes:
//
//--------------------------------------------------------------------------
NTSTATUS NTAPI
SpUserQueryContextAttributes(
IN LSA_SEC_HANDLE ContextHandle,
IN ULONG ContextAttribute,
IN OUT PVOID pBuffer
)
{
PSSL_USER_CONTEXT Context;
PSPContext pContext;
SECURITY_STATUS Status;
Context = SslFindUserContext( ContextHandle );
if(Context == NULL)
{
return(SEC_E_INVALID_HANDLE);
}
pContext = Context->pContext;
if(!pContext)
{
return(SEC_E_INVALID_HANDLE);
}
switch(ContextAttribute)
{
case SECPKG_ATTR_CONNECTION_INFO:
Status = SpQueryConnectionInfo(pContext, pBuffer);
break;
case SECPKG_ATTR_KEY_INFO:
Status = SpQueryKeyInfo(pContext, pBuffer);
break;
case SECPKG_ATTR_LIFESPAN:
Status = SpQueryLifespan(pContext, pBuffer);
break;
case SECPKG_ATTR_NAMES :
Status = SpQueryNames(pContext, pBuffer);
break;
case SECPKG_ATTR_PACKAGE_INFO:
Status = SpQueryPackageInfo(pContext, pBuffer);
break;
case SECPKG_ATTR_PROTO_INFO:
Status = SpQueryProtoInfo(pContext, pBuffer);
break;
case SECPKG_ATTR_REMOTE_CERT_CONTEXT:
Status = SpQueryRemoteCertContext(pContext, pBuffer);
break;
case SECPKG_ATTR_REMOTE_CRED:
Status = SpQueryRemoteCred(pContext, pBuffer);
break;
case SECPKG_ATTR_SIZES:
Status = SpQuerySizes(pContext, pBuffer);
break;
case SECPKG_ATTR_STREAM_SIZES:
Status = SpQueryStreamSizes(pContext, pBuffer);
break;
case SECPKG_ATTR_ACCESS_TOKEN:
Status = SpQueryAccessToken(pContext, pBuffer);
break;
case SECPKG_ATTR_SESSION_INFO:
Status = SpQuerySessionInfo(pContext, pBuffer);
break;
default:
DebugLog((DEB_ERROR, "QueryContextAttributes(unsupported function %d)\n", ContextAttribute));
return SP_LOG_RESULT(SEC_E_UNSUPPORTED_FUNCTION);
}
return Status;
}
//+-------------------------------------------------------------------------
//
// Function: SpSetUseValidatedProp
//
// Synopsis: Sets the SECPKG_ATTR_USE_VALIDATED context attribute.
//
// Arguments:
//
// Returns:
//
// Notes: The buffer must contain a DWORD indicating whether the
// credential currently associated with the context has been
// validated for use.
//
//--------------------------------------------------------------------------
NTSTATUS
SpSetUseValidatedProp(
IN PSPContext pContext,
IN PVOID Buffer,
IN ULONG BufferSize)
{
DWORD dwUseValidated;
NTSTATUS Status;
DebugLog((DEB_TRACE, "SetContextAttributes(SECPKG_ATTR_USE_VALIDATED)\n"));
if(BufferSize < sizeof(DWORD))
{
Status = SP_LOG_RESULT(STATUS_INVALID_PARAMETER);
goto cleanup;
}
Status = LsaTable->CopyFromClientBuffer( NULL,
sizeof(DWORD),
&dwUseValidated,
Buffer );
if(FAILED(Status))
{
SP_LOG_RESULT(Status);
goto cleanup;
}
DebugLog((DEB_TRACE, "Use validated:%d\n", dwUseValidated));
if(pContext->RipeZombie == NULL)
{
Status = SP_LOG_RESULT(STATUS_INVALID_PARAMETER);
goto cleanup;
}
if(dwUseValidated)
{
pContext->RipeZombie->dwFlags |= SP_CACHE_FLAG_USE_VALIDATED;
}
else
{
pContext->RipeZombie->dwFlags &= ~SP_CACHE_FLAG_USE_VALIDATED;
}
cleanup:
return Status;
}
//+-------------------------------------------------------------------------
//
// Function: SpSetCredentialNameProp
//
// Synopsis: Sets the SECPKG_ATTR_CREDENTIAL_NAME context attribute.
//
// Arguments:
//
// Returns:
//
// Notes: The buffer must contain the following structure:
//
// typedef struct _SecPkgContext_CredentialNameW
// {
// unsigned long CredentialType;
// SEC_WCHAR SEC_FAR *sCredentialName;
// } SecPkgContext_CredentialNameW, SEC_FAR * PSecPkgContext_CredentialNameW;
//
//--------------------------------------------------------------------------
NTSTATUS
SpSetCredentialNameProp(
IN PSPContext pContext,
IN PVOID Buffer,
IN ULONG BufferSize)
{
PSecPkgContext_CredentialNameW pCredentialStruct = NULL;
SEC_WCHAR *pClientCredName = NULL;
SEC_WCHAR *pCredName = NULL;
DWORD_PTR Offset;
NTSTATUS Status;
ULONG i;
BOOL fTerminated = FALSE;
DebugLog((DEB_TRACE, "SetContextAttributes(SECPKG_ATTR_CREDENTIAL_NAME)\n"));
//
// Marshal over the credential name from the client address space.
//
if(BufferSize < sizeof(SecPkgContext_CredentialNameW))
{
Status = SP_LOG_RESULT(STATUS_INVALID_PARAMETER);
goto cleanup;
}
if(BufferSize > sizeof(SecPkgContext_CredentialNameW) +
CRED_MAX_DOMAIN_TARGET_NAME_LENGTH * sizeof(WCHAR))
{
Status = SP_LOG_RESULT(STATUS_INVALID_PARAMETER);
goto cleanup;
}
pCredentialStruct = SPExternalAlloc(BufferSize + sizeof(WCHAR));
if(pCredentialStruct == NULL)
{
Status = SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
goto cleanup;
}
Status = LsaTable->CopyFromClientBuffer( NULL,
BufferSize,
pCredentialStruct,
Buffer );
if(FAILED(Status))
{
SP_LOG_RESULT(Status);
goto cleanup;
}
if(pCredentialStruct->CredentialType != CRED_TYPE_DOMAIN_CERTIFICATE)
{
DebugLog((DEB_ERROR, "Unexpected credential type %d\n", pCredentialStruct->CredentialType));
Status = SEC_E_UNKNOWN_CREDENTIALS;
goto cleanup;
}
// Get pointer to credential name in the client's address space.
pClientCredName = pCredentialStruct->sCredentialName;
if(!POINTER_IS_ALIGNED(pClientCredName, sizeof(WCHAR)))
{
Status = SP_LOG_RESULT(STATUS_INVALID_PARAMETER);
goto cleanup;
}
if((PBYTE)pClientCredName < (PBYTE)Buffer + sizeof(SecPkgContext_CredentialNameW) ||
(PBYTE)pClientCredName >= (PBYTE)Buffer + BufferSize)
{
Status = SP_LOG_RESULT(STATUS_INVALID_PARAMETER);
goto cleanup;
}
// Compute offset of credential name within the input buffer.
Offset = (PBYTE)pClientCredName - (PBYTE)Buffer;
// Build pointer to credential name in the local process.
pCredName = (SEC_WCHAR *)((PBYTE)pCredentialStruct + Offset);
// Ensure that the credential name is zero terminated.
for(i = 0; i < (BufferSize - Offset) / sizeof(WCHAR); i++)
{
if(pCredName[i] == L'\0')
{
fTerminated = TRUE;
break;
}
}
if(!fTerminated)
{
Status = SP_LOG_RESULT(STATUS_INVALID_PARAMETER);
goto cleanup;
}
DebugLog((DEB_TRACE, "Set client credential to '%ls'.\n", pCredName));
//
// Associate the specified credential with the current context.
//
pContext->pszCredentialName = SPExternalAlloc((lstrlenW(pCredName) + 1) * sizeof(WCHAR));
if(pContext->pszCredentialName == NULL)
{
Status = SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
goto cleanup;
}
lstrcpyW(pContext->pszCredentialName, pCredName);
Status = QueryCredentialManagerForCert(pContext, pCredName);
if(FAILED(Status))
{
SP_LOG_RESULT(Status);
goto cleanup;
}
DebugLog((DEB_TRACE, "Credential assigned to context successfully.\n"));
cleanup:
if(pCredentialStruct)
{
SPExternalFree(pCredentialStruct);
}
return Status;
}
//+-------------------------------------------------------------------------
//
// Function: SpSetApplicationData
//
// Synopsis: Sets the SECPKG_ATTR_APP_DATA context attribute.
//
// Arguments:
//
// Returns:
//
// Notes: The buffer must contain the following structure:
//
// typedef struct _SecPkgContext_SessionAppData
// {
// DWORD dwFlags;
// DWORD cbAppData;
// PBYTE pbAppData;
// } SecPkgContext_SessionAppData, *PSecPkgContext_SessionAppData;
//
//--------------------------------------------------------------------------
NTSTATUS
SpSetApplicationData(
IN PSPContext pContext,
IN PVOID Buffer,
IN ULONG BufferSize)
{
SecPkgContext_SessionAppData AppData;
PBYTE pbAppData = NULL;
NTSTATUS Status;
DebugLog((DEB_TRACE, "SetContextAttributes(SECPKG_ATTR_APP_DATA)\n"));
if(pContext->RipeZombie == NULL)
{
return SP_LOG_RESULT(SEC_E_INVALID_HANDLE);
}
//
// Marshal over the input structure from the client address space.
//
if(BufferSize < sizeof(SecPkgContext_SessionAppData))
{
Status = SP_LOG_RESULT(STATUS_INVALID_PARAMETER);
goto cleanup;
}
Status = LsaTable->CopyFromClientBuffer( NULL,
sizeof(SecPkgContext_SessionAppData),
&AppData,
Buffer );
if(FAILED(Status))
{
SP_LOG_RESULT(Status);
goto cleanup;
}
//
// Marshal over the application data from the client address space.
//
// Limit application data size to 64k.
if(AppData.cbAppData > 0x10000)
{
Status = SP_LOG_RESULT(STATUS_INVALID_PARAMETER);
goto cleanup;
}
if(AppData.cbAppData == 0 || AppData.pbAppData == NULL)
{
Status = SP_LOG_RESULT(STATUS_INVALID_PARAMETER);
goto cleanup;
}
pbAppData = SPExternalAlloc(AppData.cbAppData);
if(pbAppData == NULL)
{
Status = SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
goto cleanup;
}
Status = LsaTable->CopyFromClientBuffer( NULL,
AppData.cbAppData,
pbAppData,
AppData.pbAppData );
if(FAILED(Status))
{
SP_LOG_RESULT(Status);
goto cleanup;
}
//
// Assign application data to cache entry.
//
Status = SetCacheAppData(pContext->RipeZombie,
pbAppData,
AppData.cbAppData);
if(!FAILED(Status))
{
// The operation succeeded, so consume the application data.
pbAppData = NULL;
}
cleanup:
if(pbAppData)
{
SPExternalFree(pbAppData);
}
return Status;
}
NTSTATUS
NTAPI
SpSetContextAttributes(
IN LSA_SEC_HANDLE ContextHandle,
IN ULONG ContextAttribute,
IN PVOID Buffer,
IN ULONG BufferSize)
{
NTSTATUS Status;
PSPContext pContext;
pContext = (PSPContext)ContextHandle;
switch(ContextAttribute)
{
case SECPKG_ATTR_USE_VALIDATED:
DebugLog((DEB_TRACE, "SetContextAttributes(SECPKG_ATTR_USE_VALIDATED)\n"));
Status = STATUS_SUCCESS;
break;
case SECPKG_ATTR_CREDENTIAL_NAME:
Status = SpSetCredentialNameProp(pContext, Buffer, BufferSize);
break;
case SECPKG_ATTR_TARGET_INFORMATION:
DebugLog((DEB_TRACE, "SetContextAttributes(SECPKG_ATTR_TARGET_INFORMATION)\n"));
Status = STATUS_SUCCESS;
break;
case SECPKG_ATTR_APP_DATA:
Status = SpSetApplicationData(pContext, Buffer, BufferSize);
break;
default:
DebugLog((DEB_ERROR, "SetContextAttributes(unsupported function %d)\n", ContextAttribute));
Status = SP_LOG_RESULT(SEC_E_UNSUPPORTED_FUNCTION);
}
return Status;
}