windows-nt/Source/XPSP1/NT/ds/security/protocols/schannel/lsa/stubs.c
2020-09-26 16:20:57 +08:00

622 lines
15 KiB
C

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1995.
//
// File: stubs.c
//
// Contents:
//
// Classes:
//
// Functions:
//
// History: 8-01-95 RichardW Created
//
//----------------------------------------------------------------------------
#include "sslp.h"
#include "spsspi.h"
#include <cert509.h>
#include <rsa.h>
CHAR CertTag[ 13 ] = { 0x04, 0x0b, 'c', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e' };
SecurityFunctionTableW SPFunctionTable = {
SECURITY_SUPPORT_PROVIDER_INTERFACE_VERSION,
EnumerateSecurityPackagesW,
NULL,
AcquireCredentialsHandleW,
FreeCredentialsHandle,
NULL,
InitializeSecurityContextW,
AcceptSecurityContext,
CompleteAuthToken,
DeleteSecurityContext,
ApplyControlToken,
QueryContextAttributesW,
ImpersonateSecurityContext,
RevertSecurityContext,
MakeSignature,
VerifySignature,
FreeContextBuffer,
QuerySecurityPackageInfoW,
SealMessage,
UnsealMessage,
NULL, /* GrantProxyW */
NULL, /* RevokeProxyW */
NULL, /* InvokeProxyW */
NULL, /* RenewProxyW */
QuerySecurityContextToken,
SealMessage,
UnsealMessage,
SetContextAttributesW
};
SecurityFunctionTableA SPFunctionTableA = {
SECURITY_SUPPORT_PROVIDER_INTERFACE_VERSION,
EnumerateSecurityPackagesA,
NULL,
AcquireCredentialsHandleA,
FreeCredentialsHandle,
NULL,
InitializeSecurityContextA,
AcceptSecurityContext,
CompleteAuthToken,
DeleteSecurityContext,
ApplyControlToken,
QueryContextAttributesA,
ImpersonateSecurityContext,
RevertSecurityContext,
MakeSignature,
VerifySignature,
FreeContextBuffer,
QuerySecurityPackageInfoA,
SealMessage,
UnsealMessage,
NULL, /* GrantProxyA */
NULL, /* RevokeProxyA */
NULL, /* InvokeProxyA */
NULL, /* RenewProxyA */
QuerySecurityContextToken,
SealMessage,
UnsealMessage,
SetContextAttributesA
};
PSecurityFunctionTableW SEC_ENTRY
InitSecurityInterfaceW(
VOID )
{
return(&SPFunctionTable);
}
PSecurityFunctionTableA SEC_ENTRY
InitSecurityInterfaceA(
VOID )
{
return(&SPFunctionTableA);
}
SECURITY_STATUS SEC_ENTRY
FreeContextBuffer(
void SEC_FAR * pvContextBuffer
)
{
SPExternalFree( pvContextBuffer );
return(SEC_E_OK);
}
SECURITY_STATUS SEC_ENTRY
SecurityPackageControl(
SEC_WCHAR SEC_FAR * pszPackageName,
unsigned long dwFunctionCode,
unsigned long cbInputBuffer,
unsigned char SEC_FAR * pbInputBuffer,
unsigned long SEC_FAR * pcbOutputBuffer,
unsigned char SEC_FAR * pbOutputBuffer)
{
return(SEC_E_UNSUPPORTED_FUNCTION);
}
SECURITY_STATUS PctTranslateError(SP_STATUS spRet)
{
if(HRESULT_FACILITY(spRet) == FACILITY_SECURITY)
{
return (spRet);
}
switch(spRet) {
case PCT_ERR_OK: return SEC_E_OK;
case PCT_ERR_BAD_CERTIFICATE: return SEC_E_INVALID_TOKEN;
case PCT_ERR_CLIENT_AUTH_FAILED: return SEC_E_INVALID_TOKEN;
case PCT_ERR_ILLEGAL_MESSAGE: return SEC_E_INVALID_TOKEN;
case PCT_ERR_INTEGRITY_CHECK_FAILED: return SEC_E_MESSAGE_ALTERED;
case PCT_ERR_SERVER_AUTH_FAILED: return SEC_E_INVALID_TOKEN;
case PCT_ERR_SPECS_MISMATCH: return SEC_E_ALGORITHM_MISMATCH;
case PCT_ERR_SSL_STYLE_MSG: return SEC_E_INVALID_TOKEN;
case SEC_I_INCOMPLETE_CREDENTIALS: return SEC_I_INCOMPLETE_CREDENTIALS;
case PCT_ERR_RENEGOTIATE: return SEC_I_RENEGOTIATE;
case PCT_ERR_UNKNOWN_CREDENTIAL: return SEC_E_UNKNOWN_CREDENTIALS;
case CERT_E_UNTRUSTEDROOT: return SEC_E_UNTRUSTED_ROOT;
case CERT_E_EXPIRED: return SEC_E_CERT_EXPIRED;
case CERT_E_VALIDITYPERIODNESTING: return SEC_E_CERT_EXPIRED;
case CERT_E_REVOKED: return CRYPT_E_REVOKED;
case CERT_E_CN_NO_MATCH: return SEC_E_WRONG_PRINCIPAL;
case PCT_INT_BAD_CERT: return SEC_E_INVALID_TOKEN;
case PCT_INT_CLI_AUTH: return SEC_E_INVALID_TOKEN;
case PCT_INT_ILLEGAL_MSG: return SEC_E_INVALID_TOKEN;
case PCT_INT_SPECS_MISMATCH: return SEC_E_ALGORITHM_MISMATCH;
case PCT_INT_INCOMPLETE_MSG: return SEC_E_INCOMPLETE_MESSAGE;
case PCT_INT_MSG_ALTERED: return SEC_E_MESSAGE_ALTERED;
case PCT_INT_INTERNAL_ERROR: return SEC_E_INTERNAL_ERROR;
case PCT_INT_DATA_OVERFLOW: return SEC_E_INTERNAL_ERROR;
case SEC_E_INCOMPLETE_CREDENTIALS: return SEC_E_INCOMPLETE_CREDENTIALS;
case PCT_INT_RENEGOTIATE: return SEC_I_RENEGOTIATE;
case PCT_INT_UNKNOWN_CREDENTIAL: return SEC_E_UNKNOWN_CREDENTIALS;
case PCT_INT_BUFF_TOO_SMALL: return SEC_E_BUFFER_TOO_SMALL;
case SEC_E_BUFFER_TOO_SMALL: return SEC_E_BUFFER_TOO_SMALL;
default: return SEC_E_INTERNAL_ERROR;
}
}
//+---------------------------------------------------------------------------
//
// Function: SslGenerateRandomBits
//
// Synopsis: Hook for setup to get a good random stream
//
// Arguments: [pRandomData] --
// [cRandomData] --
//
//
// Notes:
//
//----------------------------------------------------------------------------
VOID
WINAPI
SslGenerateRandomBits(
PUCHAR pRandomData,
LONG cRandomData
)
{
if(!SchannelInit(TRUE))
{
return;
}
GenerateRandomBits(pRandomData, (ULONG)cRandomData);
}
//+---------------------------------------------------------------------------
//
// Function: SslGenerateKeyPair
//
// Synopsis: Generates a public/private key pair, protected by password
//
// Arguments: [pCerts] --
// [pszDN] --
// [pszPassword] --
// [Bits] --
//
// Notes:
//
//----------------------------------------------------------------------------
BOOL
WINAPI
SslGenerateKeyPair(
PSSL_CREDENTIAL_CERTIFICATE pCerts,
PSTR pszDN,
PSTR pszPassword,
DWORD Bits )
{
if(!SchannelInit(TRUE))
{
return FALSE;
}
#ifdef SCHANNEL_EXPORT
if ( Bits > 1024 )
{
SetLastError( ERROR_INVALID_PARAMETER );
return( FALSE );
}
#endif
return GenerateKeyPair(pCerts, pszDN, pszPassword, Bits);
}
//+---------------------------------------------------------------------------
//
// Function: SslGetMaximumKeySize
//
// Synopsis: Returns maximum public key size
//
// Arguments: [Reserved] --
//
// Notes:
//
//----------------------------------------------------------------------------
DWORD
WINAPI
SslGetMaximumKeySize(
DWORD Reserved )
{
#ifdef SCHANNEL_EXPORT
return( 1024 );
#else
return( 2048 );
#endif
}
//+---------------------------------------------------------------------------
//
// Function: SslFreeCertificate
//
// Synopsis: Frees a certificate created from SslCrackCertificate
//
// Arguments: [pCertificate] --
//
// Notes:
//
//----------------------------------------------------------------------------
VOID
WINAPI
SslFreeCertificate(
PX509Certificate pCertificate)
{
if ( pCertificate )
{
SPExternalFree(pCertificate->pPublicKey);
SPExternalFree(pCertificate);
}
}
//+---------------------------------------------------------------------------
//
// Function: SslCrackCertificate
//
// Synopsis: Cracks a X509 certificate into remotely easy format
//
// Arguments: [pbCertificate] --
// [cbCertificate] --
// [dwFlags] --
// [ppCertificate] --
//
// Notes:
//
//----------------------------------------------------------------------------
BOOL
WINAPI
SslCrackCertificate(
PUCHAR pbCertificate,
DWORD cbCertificate,
DWORD dwFlags,
PX509Certificate * ppCertificate)
{
PX509Certificate pResult = NULL;
PCCERT_CONTEXT pContext = NULL;
DWORD cbIssuer;
DWORD cbSubject;
if(!SchannelInit(TRUE))
{
return FALSE;
}
if (dwFlags & CF_CERT_FROM_FILE)
{
if (cbCertificate < CERT_HEADER_LEN + 1 )
{
goto error;
}
//
// Sleazy quick check. Some CAs wrap certs in a cert wrapper.
// Some don't. Some do both, but we won't mention any names.
// Quick check for the wrapper tag. If so, scoot in by enough
// to bypass it (17 bytes. Sheesh).
//
if ( memcmp( pbCertificate + 4, CertTag, sizeof( CertTag ) ) == 0 )
{
pbCertificate += CERT_HEADER_LEN;
cbCertificate -= CERT_HEADER_LEN;
}
}
pContext = CertCreateCertificateContext(X509_ASN_ENCODING, pbCertificate, cbCertificate);
if(pContext == NULL)
{
SP_LOG_RESULT(GetLastError());
goto error;
}
if(0 >= (cbSubject = CertNameToStrA(pContext->dwCertEncodingType,
&pContext->pCertInfo->Subject,
CERT_X500_NAME_STR | CERT_NAME_STR_NO_PLUS_FLAG,
NULL, 0)))
{
SP_LOG_RESULT(GetLastError());
goto error;
}
if(0 >= (cbIssuer = CertNameToStrA(pContext->dwCertEncodingType,
&pContext->pCertInfo->Issuer,
CERT_X500_NAME_STR | CERT_NAME_STR_NO_PLUS_FLAG,
NULL, 0)))
{
SP_LOG_RESULT(GetLastError());
goto error;
}
pResult = SPExternalAlloc(sizeof(X509Certificate) + cbIssuer + cbSubject + 2);
if(pResult == NULL)
{
goto error;
}
pResult->pPublicKey = NULL;
pResult->pszIssuer = (PUCHAR)(pResult + 1);
pResult->pszSubject = pResult->pszIssuer + cbIssuer;
pResult->Version = pContext->pCertInfo->dwVersion;
memcpy(pResult->SerialNumber,
pContext->pCertInfo->SerialNumber.pbData,
min(sizeof(pResult->SerialNumber), pContext->pCertInfo->SerialNumber.cbData));
pResult->ValidFrom = pContext->pCertInfo->NotBefore;
pResult->ValidUntil = pContext->pCertInfo->NotAfter;
if(0 >= CertNameToStrA(pContext->dwCertEncodingType,
&pContext->pCertInfo->Issuer,
CERT_X500_NAME_STR | CERT_NAME_STR_NO_PLUS_FLAG,
pResult->pszIssuer, cbIssuer))
{
SP_LOG_RESULT(GetLastError());
goto error;
}
if(0 >= CertNameToStrA(pContext->dwCertEncodingType,
&pContext->pCertInfo->Subject,
CERT_X500_NAME_STR | CERT_NAME_STR_NO_PLUS_FLAG,
pResult->pszSubject, cbSubject))
{
SP_LOG_RESULT(GetLastError());
goto error;
}
{
BSAFE_PUB_KEY *pk;
PUBLICKEY * pPubKey = NULL;
SP_STATUS pctRet;
DWORD cbPublicKey;
pResult->pPublicKey = SPExternalAlloc(sizeof(PctPublicKey) + sizeof(BSAFE_PUB_KEY));
if(pResult->pPublicKey == NULL)
{
goto error;
}
pResult->pPublicKey->Type = 0;
pResult->pPublicKey->cbKey = sizeof(BSAFE_PUB_KEY);
pk = (BSAFE_PUB_KEY *)pResult->pPublicKey->pKey;
pk->magic = RSA1;
pctRet = SPPublicKeyFromCert(pContext, &pPubKey, NULL);
if(pctRet == PCT_ERR_OK)
{
if(pPubKey->pPublic->aiKeyAlg == CALG_RSA_KEYX)
{
RSAPUBKEY *pRsaKey = (RSAPUBKEY *)(pPubKey->pPublic + 1);
pk->keylen = pRsaKey->bitlen/8;
pk->bitlen = pRsaKey->bitlen;
pk->datalen = pk->bitlen/8 - 1;
pk->pubexp = pRsaKey->pubexp;
}
else
{
DHPUBKEY *pDHKey = (DHPUBKEY *)(pPubKey->pPublic + 1);
pk->keylen = pDHKey->bitlen/8;
pk->bitlen = pDHKey->bitlen/8;
pk->datalen = pk->bitlen/8 - 1;
pk->pubexp = 0;
}
SPExternalFree(pPubKey);
}
else
{
goto error;
}
}
CertFreeCertificateContext(pContext);
*ppCertificate = pResult;
return TRUE;
error:
if(pContext)
{
CertFreeCertificateContext(pContext);
}
if(pResult)
{
if(pResult->pPublicKey)
{
SPExternalFree(pResult->pPublicKey);
}
SPExternalFree(pResult);
}
return FALSE;
}
//+---------------------------------------------------------------------------
//
// Function: SslLoadCertificate
//
// Synopsis: Not supported.
//
// Notes:
//
//----------------------------------------------------------------------------
BOOL
WINAPI
SslLoadCertificate(
PUCHAR pbCertificate,
DWORD cbCertificate,
BOOL AddToWellKnownKeys)
{
return FALSE;
}
BOOL
SslGetClientProcess(ULONG *pProcessID)
{
SECPKG_CALL_INFO CallInfo;
SECURITY_STATUS Status;
if(LsaTable == NULL)
{
*pProcessID = GetCurrentProcessId();
return TRUE;
}
if(LsaTable->GetCallInfo(&CallInfo))
{
*pProcessID = CallInfo.ProcessId;
return TRUE;
}
else
{
*pProcessID = -1;
return FALSE;
}
}
BOOL
SslGetClientThread(ULONG *pThreadID)
{
SECPKG_CALL_INFO CallInfo;
SECURITY_STATUS Status;
if(LsaTable == NULL)
{
*pThreadID = GetCurrentThreadId();
return TRUE;
}
if(LsaTable->GetCallInfo(&CallInfo))
{
*pThreadID = CallInfo.ThreadId;
return TRUE;
}
else
{
*pThreadID = -1;
return FALSE;
}
}
BOOL
SslImpersonateClient(void)
{
SECPKG_CALL_INFO CallInfo;
SECURITY_STATUS Status;
// Don't impersonate if we're in the client process.
if(LsaTable == NULL)
{
return FALSE;
}
// Don't impersonate if the client is running in the lsass process.
if(LsaTable->GetCallInfo(&CallInfo))
{
if(CallInfo.ProcessId == GetCurrentProcessId())
{
// DebugLog((DEB_WARN, "Running locally, so don't impersonate.\n"));
return FALSE;
}
}
Status = LsaTable->ImpersonateClient();
if(!NT_SUCCESS(Status))
{
SP_LOG_RESULT(Status);
return FALSE;
}
return TRUE;
}
NTSTATUS
SslGetClientLogonId(LUID *pLogonId)
{
SECPKG_CLIENT_INFO ClientInfo;
SECURITY_STATUS Status;
memset(pLogonId, 0, sizeof(LUID));
Status = LsaTable->GetClientInfo(&ClientInfo);
if(NT_SUCCESS(Status))
{
*pLogonId = ClientInfo.LogonId;
}
return Status;
}
PVOID SPExternalAlloc(DWORD cbLength)
{
if(LsaTable)
{
// Lsass process
return LsaTable->AllocateLsaHeap(cbLength);
}
else
{
// Application process
return LocalAlloc(LPTR, cbLength);
}
}
VOID SPExternalFree(PVOID pMemory)
{
if(LsaTable)
{
// Lsass process
LsaTable->FreeLsaHeap(pMemory);
}
else
{
// Application process
LocalFree(pMemory);
}
}