📄 model.cpp
字号:
#include "precomp.h"
#include "model.h"
static BYTE s_rawbuf[4096 * 4];
Model::Model(bool bServer, ERR_FCN errFcn)
: m_bServer(bServer),
m_errFcn(errFcn),
m_state(msChoosingSSP),
m_credMethod(cmNormal),
m_grfContextRequirements(0),
m_hdll(0),
m_pSSPI(0),
m_bCalledAcceptYet(false)
{
_ASSERT(m_errFcn);
ZeroMemory(m_szSSP, sizeof m_szSSP);
ZeroMemory(m_szSSPList, sizeof m_szSSPList);
ZeroMemory(m_szAuthority, sizeof m_szAuthority);
ZeroMemory(m_szPrincipal, sizeof m_szPrincipal);
ZeroMemory(m_szPassword, sizeof m_szPassword);
ZeroMemory(&m_authIdentity, sizeof m_authIdentity);
ZeroMemory(&m_credExpiry, sizeof m_credExpiry);
ZeroMemory(&m_ctxExpiry, sizeof m_ctxExpiry);
SecInvalidateHandle(&m_hcred);
SecInvalidateHandle(&m_hctx);
m_authIdentity.Version = SEC_WINNT_AUTH_IDENTITY_VERSION;
m_authIdentity.Length = sizeof m_authIdentity;
m_authIdentity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
m_hdll = LoadLibrary(L"security.dll");
if (!m_hdll)
_err(L"LoadLibrary");
INIT_SECURITY_INTERFACE_W initSecurityInterface = (INIT_SECURITY_INTERFACE_W)GetProcAddress(m_hdll, SECURITY_ENTRYPOINT_ANSIW);
if (!initSecurityInterface)
_err(L"GetProcAddress");
m_pSSPI = initSecurityInterface();
if (!m_pSSPI)
_err(L"InitSecurityInterface");
}
Model::~Model() {
if (m_pSSPI) {
m_pSSPI->DeleteSecurityContext(&m_hctx);
m_pSSPI->FreeCredentialsHandle(&m_hcred);
}
if (m_hdll)
FreeLibrary(m_hdll);
}
void Model::chooseSpecificSSP(const wchar_t* pszSSP) {
_ASSERT(msChoosingSSP == m_state);
_ASSERT(lstrlen(pszSSP) < sizeof m_szSSP / sizeof *m_szSSP);
lstrcpy(m_szSSP, pszSSP);
m_state = msChoosingCredentials;
}
void Model::chooseSPNEGO(const wchar_t* pszSSPList) {
_ASSERT(msChoosingSSP == m_state);
_ASSERT(lstrlen(pszSSPList) < sizeof m_szSSPList / sizeof *m_szSSPList);
lstrcpy(m_szSSPList, pszSSPList);
lstrcpy(m_szSSP, L"Negotiate");
m_authIdentity.PackageList = m_szSSPList;
m_authIdentity.PackageListLength = lstrlen(m_authIdentity.PackageList);
m_state = msChoosingCredentials;
}
void Model::chooseCredentials(const LUID* pLogonSessionLuid) {
_ASSERT(msChoosingCredentials == m_state);
// only pass in the authIdentity struct if we're using SPNEGO
void* pAuthIdentity = 0;
if (m_authIdentity.PackageList)
pAuthIdentity = &m_authIdentity;
SECURITY_STATUS err =
m_pSSPI->AcquireCredentialsHandle(0,
m_szSSP,
m_bServer ? SECPKG_CRED_INBOUND : SECPKG_CRED_OUTBOUND,
const_cast<LUID*>(pLogonSessionLuid),
pAuthIdentity,
0, 0,
&m_hcred,
&m_credExpiry);
if (err)
_err(L"AcquireCredentialsHandle", false, err);
m_state = m_bServer ? msAuthenticating : msChoosingContextRequirements;
}
void Model::chooseCredentials(const wchar_t* pszAuthority,
const wchar_t* pszPrincipal,
const wchar_t* pszPassword) {
_ASSERT(msChoosingCredentials == m_state);
_ASSERT(lstrlen(pszAuthority) < sizeof m_szAuthority / sizeof *m_szAuthority);
_ASSERT(lstrlen(pszPrincipal) < sizeof m_szPrincipal / sizeof *m_szPrincipal);
_ASSERT(lstrlen(pszPassword) < sizeof m_szPassword / sizeof *m_szPassword);
lstrcpy(m_szAuthority, pszAuthority);
lstrcpy(m_szPrincipal, pszPrincipal);
lstrcpy(m_szPassword, pszPassword);
m_authIdentity.User = m_szPrincipal;
m_authIdentity.Domain = m_szAuthority;
m_authIdentity.Password = m_szPassword;
m_authIdentity.UserLength = lstrlen(m_authIdentity.User);
m_authIdentity.DomainLength = lstrlen(m_authIdentity.Domain);
m_authIdentity.PasswordLength = lstrlen(m_authIdentity.Password);
SECURITY_STATUS err =
m_pSSPI->AcquireCredentialsHandle(0,
m_szSSP,
m_bServer ? SECPKG_CRED_INBOUND : SECPKG_CRED_OUTBOUND,
0,
&m_authIdentity,
0, 0,
&m_hcred,
&m_credExpiry);
if (err)
_err(L"AcquireCredentialsHandle", false, err);
m_state = msChoosingContextRequirements;
}
void Model::chooseContextRequirements(DWORD grfContextRequirements) {
_ASSERT(msChoosingContextRequirements == m_state);
m_grfContextRequirements = grfContextRequirements | ISC_REQ_CONFIDENTIALITY |
ISC_REQ_REPLAY_DETECT |
ISC_REQ_SEQUENCE_DETECT |
ISC_REQ_CONNECTION;
m_state = msAuthenticating;
}
void Model::initializeSecurityContext(const wchar_t* pszServerPrincipalName,
void* pvInputRx, DWORD cbInput,
void** ppvOutputTx, DWORD* pcbOutput,
bool* pbContinueNeeded,
ULONG* pgrfCtxAttrs) {
_ASSERT(msAuthenticating == m_state);
SecBuffer sbi = {cbInput, SECBUFFER_TOKEN, pvInputRx};
SecBuffer sbo = {sizeof s_rawbuf, SECBUFFER_TOKEN, s_rawbuf};
SecBufferDesc sbdi = {SECBUFFER_VERSION, 1, &sbi};
SecBufferDesc sbdo = {SECBUFFER_VERSION, 1, &sbo};
SECURITY_STATUS err =
m_pSSPI->InitializeSecurityContext(
&m_hcred,
cbInput ? &m_hctx : 0,
const_cast<wchar_t*>(pszServerPrincipalName),
m_grfContextRequirements,
0, SECURITY_NATIVE_DREP,
&sbdi, 0,
&m_hctx,
&sbdo,
pgrfCtxAttrs,
&m_ctxExpiry);
switch (err) {
case 0:
*pbContinueNeeded = false;
break;
case SEC_I_CONTINUE_NEEDED:
*pbContinueNeeded = true;
break;
default:
_err(L"InitializeSecurityContext", false, err);
}
// determine whether there's anything to send to the server
if (sbo.cbBuffer) {
*pcbOutput = sbo.cbBuffer;
*ppvOutputTx = malloc(sbo.cbBuffer);
CopyMemory(*ppvOutputTx, sbo.pvBuffer, sbo.cbBuffer);
}
else {
*ppvOutputTx = 0;
*pcbOutput = 0;
}
if (!*pbContinueNeeded)
m_state = msAuthnComplete;
}
void Model::acceptSecurityContext(void* pvInputRx, DWORD cbInput,
void** ppvOutputTx, DWORD* pcbOutput,
bool* pbContinueNeeded,
ULONG* pgrfCtxAttrs) {
_ASSERT(msAuthenticating == m_state);
SecBuffer sbi = {cbInput, SECBUFFER_TOKEN, pvInputRx};
SecBuffer sbo = {sizeof s_rawbuf, SECBUFFER_TOKEN, s_rawbuf};
SecBufferDesc sbdi = {SECBUFFER_VERSION, 1, &sbi};
SecBufferDesc sbdo = {SECBUFFER_VERSION, 1, &sbo};
SECURITY_STATUS err =
m_pSSPI->AcceptSecurityContext(
&m_hcred,
m_bCalledAcceptYet ? &m_hctx : 0,
&sbdi,
m_grfContextRequirements,
SECURITY_NATIVE_DREP,
&m_hctx,
&sbdo,
pgrfCtxAttrs,
&m_ctxExpiry);
m_bCalledAcceptYet = true;
switch (err) {
case 0:
*pbContinueNeeded = false;
break;
case SEC_I_CONTINUE_NEEDED:
*pbContinueNeeded = true;
break;
default:
// I ignore SEC_I_COMPLETE_XXXX for simplicity, as it doesn't occur in the
// SSPI modes that I support (I think this may be used with datagram SSPI contexts)
_err(L"InitializeSecurityContext", false, err);
}
// determine whether there's anything to send to the server
if (sbo.cbBuffer) {
*pcbOutput = sbo.cbBuffer;
*ppvOutputTx = malloc(sbo.cbBuffer);
CopyMemory(*ppvOutputTx, sbo.pvBuffer, sbo.cbBuffer);
}
else {
*ppvOutputTx = 0;
*pcbOutput = 0;
}
if (!*pbContinueNeeded)
m_state = msAuthnComplete;
}
void Model::impersonate() {
SECURITY_STATUS err = m_pSSPI->ImpersonateSecurityContext(&m_hctx);
if (err)
_err(L"ImpersonateSecurityContext");
}
void Model::revert() {
SECURITY_STATUS err = m_pSSPI->RevertSecurityContext(&m_hctx);
if (err)
_err(L"RevertSecurityContext");
}
bool Model::signMessage(const void* pvMessage, DWORD cbMessage, DWORD nSeqNo,
void** ppvSignedMessage, DWORD* pcbSignedMessage) {
_ASSERT(msAuthnComplete == m_state);
SecPkgContext_Sizes sizes;
m_pSSPI->QueryContextAttributes(&m_hctx, SECPKG_ATTR_SIZES, &sizes);
*ppvSignedMessage = malloc(cbMessage + sizes.cbMaxSignature);
CopyMemory(*ppvSignedMessage, pvMessage, cbMessage);
SecBuffer rgsb[] = {
{cbMessage, SECBUFFER_DATA, *ppvSignedMessage},
{sizes.cbMaxSignature, SECBUFFER_TOKEN, static_cast<BYTE*>(*ppvSignedMessage) + cbMessage},
};
SecBufferDesc sbd = {SECBUFFER_VERSION, sizeof rgsb / sizeof *rgsb, rgsb};
SECURITY_STATUS err = m_pSSPI->MakeSignature(&m_hctx, 0, &sbd, nSeqNo);
bool bOk = true;
if (err) {
_err(L"MakeSignature", false, err);
bOk = false;
free(*ppvSignedMessage);
*ppvSignedMessage = 0;
}
*pcbSignedMessage = cbMessage + rgsb[1].cbBuffer;
return bOk;
}
bool Model::encryptMessage(const void* pvMessage, DWORD cbMessage, DWORD nSeqNo,
void** ppvSealedMessage, DWORD* pcbSealedMessage) {
_ASSERT(msAuthnComplete == m_state);
SecPkgContext_Sizes sizes;
SECURITY_STATUS err = m_pSSPI->QueryContextAttributes(&m_hctx, SECPKG_ATTR_SIZES, &sizes);
if (err)
_err(L"QueryContextAttributes", false, err);
// SSPI docs are not at ALL clear on how to form encrypted messages using a non-stream SSP
*ppvSealedMessage = malloc(cbMessage + sizes.cbSecurityTrailer);
CopyMemory(*ppvSealedMessage, pvMessage, cbMessage);
SecBuffer rgsb[] = {
{cbMessage, SECBUFFER_DATA, *ppvSealedMessage},
{sizes.cbSecurityTrailer, SECBUFFER_TOKEN, static_cast<BYTE*>(*ppvSealedMessage) + cbMessage},
};
SecBufferDesc sbd = {SECBUFFER_VERSION, sizeof rgsb / sizeof *rgsb, rgsb};
err = m_pSSPI->EncryptMessage(&m_hctx, 0, &sbd, nSeqNo);
bool bOk = true;
if (err) {
_err(L"EncryptMessage", false, err);
bOk = false;
free(*ppvSealedMessage);
*ppvSealedMessage = 0;
}
*pcbSealedMessage = cbMessage + rgsb[1].cbBuffer;
return bOk;
}
bool Model::verifySignature(const void* pvSignedMessage, DWORD cbSignedMessage, DWORD cbMessage, DWORD nSeqNo,
void** ppvMessage) {
_ASSERT(msAuthnComplete == m_state);
*ppvMessage = malloc(cbSignedMessage);
CopyMemory(*ppvMessage, pvSignedMessage, cbSignedMessage);
const DWORD cbSig = cbSignedMessage - cbMessage;
SecBuffer rgsb[] = {
{cbMessage, SECBUFFER_DATA, *ppvMessage},
{cbSig, SECBUFFER_TOKEN, static_cast<BYTE*>(*ppvMessage) + cbMessage},
};
SecBufferDesc sbd = {SECBUFFER_VERSION, sizeof rgsb / sizeof *rgsb, rgsb};
ULONG qop;
SECURITY_STATUS err = m_pSSPI->VerifySignature(&m_hctx, &sbd, nSeqNo, &qop);
if (err) {
_err(L"VerifySignature", true, err);
free(*ppvMessage);
*ppvMessage = 0;
}
return 0 == err;
}
bool Model::decryptMessage(const void* pvSealedMessage, DWORD cbSealedMessage, DWORD cbMessage, DWORD nSeqNo,
void** ppvMessage) {
_ASSERT(msAuthnComplete == m_state);
*ppvMessage = malloc(cbSealedMessage);
CopyMemory(*ppvMessage, pvSealedMessage, cbSealedMessage);
const DWORD cbTrailer = cbSealedMessage - cbMessage;
SecBuffer rgsb[] = {
{cbMessage, SECBUFFER_DATA, *ppvMessage},
{cbTrailer, SECBUFFER_TOKEN, static_cast<BYTE*>(*ppvMessage) + cbMessage},
};
SecBufferDesc sbd = {SECBUFFER_VERSION, sizeof rgsb / sizeof *rgsb, rgsb};
SECURITY_STATUS err = m_pSSPI->DecryptMessage(&m_hctx, &sbd, nSeqNo, 0);
if (err) {
_err(L"DecryptMessage", false, err);
free(*ppvMessage);
*ppvMessage = 0;
}
return 0 == err;
}
void Model::enumSSPs(ULONG* pn, PSecPkgInfo* ppPkgInfo) {
SECURITY_STATUS err =
m_pSSPI->EnumerateSecurityPackages(pn, ppPkgInfo);
if (err)
_err(L"EnumerateSecurityPackages", false, err);
}
void Model::freeEnumData(PSecPkgInfo pPkgInfo) {
m_pSSPI->FreeContextBuffer(pPkgInfo);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -