⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 model.cpp

📁 sspi_workbench
💻 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 + -