|
|
//+---------------------------------------------------------------------------
//
// 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; }
|