📄 crdspec_card.cpp
字号:
/*
CRDSPEC_Card.cpp
This source file contains card specific functionality for the
WfSC (Windows for SmartCard) cards The interfaces here should be
abstract enough that the implementation can be changed for other
cards easily.
*/
#include "CRDSPEC_Card.h"
#include "CRDSPEC_Container.h"
#include "assert.h"
#include "cspconst.h"
#include "PaddingHelp.h"
#include <windows.h>
#include <stdio.h>
#include <strsafe.h>
#include <stdlib.h>
#define RSA2 ((DWORD)'R'+((DWORD)'S'<<8)+((DWORD)'A'<<16)+((DWORD)'2'<<24))
/*
CCard::CCard
Purpose:
Constructor
Params:
None.
Returns:
void
*/
CCard::CCard() : m_byPINSize(0), m_hMutex(NULL),
m_hGUILib(NULL), m_lpfnGetPin(NULL), m_lpfnNewCard(NULL),
m_ulRefCount(0), m_dwFlags(0), m_pszReaderName(NULL),
m_pbyPIN(NULL)
{
}
/*
CCard::Initialize
Purpose:
Initializes the card object
Params:
const WCHAR * const pszReaderName: the reader to attach to.
DWORD dwFlags: Flags (ie. CRYPT_SILENT, etc)
Returns:
true if it succeeds, false otherwise
*/
bool CCard::Initialize(const WCHAR * const pszReaderName, DWORD dwFlags)
{
//Copy flags
m_dwFlags = dwFlags;
//Init readername
/*if(pszReaderName && *pszReaderName != TEXT('\0'))
{
DWORD dwReaderNameLen = wcslen(pszReaderName);
m_pszReaderName = new WCHAR[dwReaderNameLen + 1];
if(!m_pszReaderName)
return false;
wcscpy(m_pszReaderName, pszReaderName);
}*/
CHandleTable* phtContainers = GetContainerList();
if(!phtContainers)
return false;
//Lock the card
if(!Lock())
return false;
//Ensure the card is ready to be used by the CSP
if(!VerifyCardFiles())
{
Unlock();
return false;
}
//Get the name of each container on the card.
bool bRet = true;
UINT16 usCookie = 0;
WCHAR szFileName[MAX_NAME_BUFFER];
BOOL lResult = 1;
DWORD len;
//lResult = hScwEnumFile(m_hProxy, WfSC_DIR_CONT, &usCookie, szFileName, MAX_CARD_BUFFER);
HANDLE hFile = fp.GetFirstChild(WfSC_DIR_CONT,szFileName);
if(fp.IsValid(hFile))
{
do
{
if(!AddContainerFile(szFileName))
{
bRet = false;
break;
}
lResult = fp.EnumFile(hFile,szFileName,&len);
} while(lResult);
CloseHandle(hFile);
}
Unlock();
return bRet;
}
/*
CCard::AddContainerFile
Purpose:
Read a container file and add the container to the list
Params:
WCHAR* pszFileName: The file that contains the container
usually of the form "####"
Returns:
bool
*/
bool CCard::AddContainerFile(WCHAR* pszFileName)
{
assert(!IsBadReadPtr(pszFileName, 1));
if(!pszFileName)
return FALSE;
//Lock the card
if(!Lock())
return FALSE;
bool bRet = false;
int iSerNum = _wtoi(pszFileName);
HANDLE hFile = NULL;
long lResult;
WCHAR* pszFullPath = NULL;
BYTE* pbyFileContents = NULL;
DWORD dwActualBytesRead;
DWORD dwSize,fileSize;
CContainer* pContainer = NULL;
pszFullPath = new WCHAR[wcslen(WfSC_DIR_CONT) + 1 + wcslen(pszFileName) + 1];
if(!pszFullPath)
goto cleanup;
wsprintf(pszFullPath, TEXT("%s/%s"), WfSC_DIR_CONT, pszFileName);
//Open the container file
//lResult = hScwCreateFile(m_hProxy, pszFullPath, NULL, &hFile);
hFile = fp.GetFile(pszFullPath);
if(!fp.IsValid(hFile))
goto cleanup;
//Free the path
delete [] pszFullPath;
pszFullPath = NULL;
//lResult = hScwGetFileLength(m_hProxy, hFile, &offFileSize);
dwSize = GetFileSize(hFile,&fileSize);
if(dwSize == 0xFFFFFFFF && GetLastError != NO_ERROR)
{
goto cleanup;
}
if(fileSize == 0)
fileSize = dwSize;
pbyFileContents = new BYTE[fileSize];
if(!pbyFileContents)
goto cleanup;
//lResult = hScwReadFile32(m_hProxy, hFile, pbyFileContents, offFileSize, &dwActualBytesRead);
lResult = fp.ReadData(hFile,pbyFileContents,fileSize,&dwActualBytesRead);
if(!lResult || dwActualBytesRead != fileSize)
goto cleanup;
pContainer = new CContainer();
if(!pContainer)
goto cleanup;
if(!pContainer->Initialize(this, iSerNum, pbyFileContents, fileSize))
{
delete pContainer;
goto cleanup;
}
if(!m_htContainers.AddToTable(pContainer))
{
delete pContainer;
goto cleanup;
}
bRet = true;
cleanup:
if(pbyFileContents)
delete [] pbyFileContents;
if(pszFullPath)
delete [] pszFullPath;
if(hFile)
CloseHandle(hFile);
Unlock();
return bRet;
}
/*
CCard::~CCard
Purpose:
Destructor
Params:
None.
Returns:
void
*/
CCard::~CCard()
{
//UnloadGuiLib();
CContainer* pCont;
int iCookie = START;
while(pCont = (CContainer*)m_htContainers.GetNext(iCookie))
{
//Free memory associated with the container
delete pCont;
}
if(m_pszReaderName)
delete [] m_pszReaderName;
if(m_pbyPIN)
{
ZeroMemory(m_pbyPIN, m_byPINSize);
delete [] m_pbyPIN;
}
}
/*
CCard::Lock
Purpose:
Locks the card reader for future use.
Params:
None.
Returns:
bool : true if it successfully locked the card, false otherwise.
*/
bool CCard::Lock()
{
//If we're attaching to this card for the first time
if(m_ulRefCount == 0)
{
//If we don't have a card mutex, get one.
if(!GenerateCardMutex())
return false;
//We shouldn't get here if we don't have a mutex.
assert(m_hMutex);
//Wait for the reader to become free...
if(WaitForSingleObject(m_hMutex, INFINITE) != WAIT_OBJECT_0)
return false;
//Attempt to attach to the card.
if(!AttachToCard())
{
ReleaseMutex(m_hMutex);
return false;
}
}
//We're in the card mutex, so it's OK if we don't use
//InterlockedIncrement.
++m_ulRefCount;
return true;
}
/*
CCard::Unlock
Purpose:
Unlocks the card after it was locked
Params:
None.
Returns:
void
*/
void CCard::Unlock()
{
//Decrement the refcount
--m_ulRefCount;
//Note that this variable is signed in debug builds
//so this assert is actually useful.
assert(m_ulRefCount >= 0);
//If there are no more locks on the card, release it
if(m_ulRefCount == 0)
{
ReleaseCard();
//We couldn't have locked if we didn't have a mutex...
assert(m_hMutex);
if(m_hMutex)
ReleaseMutex(m_hMutex);
}
}
/*
CCard::VerifyCardFiles
Purpose:
Verifies that all the files required to use this card are
in fact on the card and creates them if they're not needed.
Params:
None.
Returns:
bool : true if it succeeds, false otherwise.
*/
bool CCard::VerifyCardFiles()
{
//Attach to the card, if we haven't already
//We would simply call Lock() here except that Lock calls us.
if(!AttachToCard())
return false;
//Initialize each component of the card
//Note KPs need to be generated first since they are used
//in the ACL files.
// TUID uid;
// long lResult;
//check whether hash good
if(fp.UserInit(WfSC_KP_PATH,WfSC_USER_NAME))
return true;
fp.MakeDirs();
if(!LoadGuiLib())
return false;
bool bRet = false;
BYTE * pbyAdminPIN;
BYTE byAdminPINLen;
BYTE * pbyUserPIN;
BYTE byUserPINLen;
if(!m_lpfnNewCard(
(m_dwFlags&CRYPT_SILENT) == CRYPT_SILENT,
&pbyAdminPIN,
&byAdminPINLen,
&pbyUserPIN,
&byUserPINLen))
return false;
m_pbyPIN = new BYTE[byUserPINLen];
if(!m_pbyPIN)
goto cleanup;
memcpy(m_pbyPIN, pbyUserPIN, byUserPINLen);
m_byPINSize = byUserPINLen;
//TODO
if(!GenerateKP(WfSC_CSP_KP_USER, m_pbyPIN,m_byPINSize))
{
m_byPINSize = 0;
delete[]m_pbyPIN;
m_pbyPIN = NULL;
goto cleanup;
}
if(!fp.UserInit(WfSC_KP_PATH,WfSC_ROOT_NAME))
if(!GenerateKP(WfSC_CSP_KP_ROOT, pbyAdminPIN, byAdminPINLen))
goto cleanup;
////Note that ACL files must be generated second
////since they use KPs and are assigned to the Cont/CSP dirs
//if(!InitACLFiles())
// return false;
////Change the ACL on the KP files
////Set the ACL on the User KP
//wsprintf(szKPFile, WfSC_KP_PATH, WfSC_USER_NAME);
//hScwSetFileACL(m_hProxy, szKPFile, WfSC_ACL_USR);
////Set the ACL on the root KP
//wsprintf(szKPFile, WfSC_KP_PATH, WfSC_ROOT_NAME);
//hScwSetFileACL(m_hProxy, szKPFile, WfSC_ACL_ROT);
//These need to be created last since they use the ACL files.
if(!InitContCSPDirs())
goto cleanup;
Authenticate();
//If all of them worked, return true.
return true;
cleanup:
if(pbyAdminPIN)
{
memset(pbyAdminPIN, 0, byAdminPINLen);
m_lpfnFreeData(pbyAdminPIN);
}
if(pbyUserPIN)
{
memset(pbyUserPIN, 0, byUserPINLen);
m_lpfnFreeData(pbyUserPIN);
}
return bRet;
}
bool CCard::InitACLFiles()
{
//Should never call this function without the card being locked
//TUID uidRoot = SCW_PRINCIPALUID_INVALID;
//TUID uidUser = SCW_PRINCIPALUID_INVALID;
//if(!GetKPUIDs(uidRoot, uidUser))
// return false;
////Generate .key ACL
//BYTE byKeyAcl[] = {SCW_RESOURCEOPERATION_FILE_CRYPTO, SCW_ACLTYPE_DISJUNCTIVE, 4, 1, uidRoot, 1, uidUser,
// SCW_RESOURCEOPERATION_FILE_DELETE, SCW_ACLTYPE_DISJUNCTIVE, 4, 1, uidRoot, 1, uidUser};
//if(!GenerateFile(WfSC_ACL_KEY, WfSC_ACL_KEY, byKeyAcl, sizeof(byKeyAcl))
// && GetLastError() != SCW_E_ALREADYEXISTS)
// return false;
////Generate .lky ACL
//BYTE byLkyAcl[] = {SCW_RESOURCEOPERATION_ANY, SCW_ACLTYPE_DISJUNCTIVE, 4, 1, uidRoot, 1, uidUser};
//if(!GenerateFile(WfSC_ACL_LKY, WfSC_ACL_KEY, byLkyAcl, sizeof(byLkyAcl))
// && GetLastError() != SCW_E_ALREADYEXISTS)
// return false;
////Generate .crt ACL
//BYTE byCrtAcl[] = {SCW_RESOURCEOPERATION_FILE_WRITE, SCW_ACLTYPE_DISJUNCTIVE, 4, 1, uidRoot, 1, uidUser,
// SCW_RESOURCEOPERATION_FILE_EXTEND, SCW_ACLTYPE_DISJUNCTIVE, 4, 1, uidRoot, 1, uidUser,
// SCW_RESOURCEOPERATION_FILE_DELETE, SCW_ACLTYPE_DISJUNCTIVE, 4, 1, uidRoot, 1, uidUser,
// SCW_RESOURCEOPERATION_SETACL, SCW_ACLTYPE_DISJUNCTIVE, 4, 1, uidRoot, 1, 0xff,
// SCW_RESOURCEOPERATION_FILE_READ, SCW_ACLTYPE_DISJUNCTIVE, 2, 1, SCW_PRINCIPALUID_ANONYMOUS};
//if(!GenerateFile(WfSC_ACL_CRT, WfSC_ACL_KEY, byCrtAcl, sizeof(byCrtAcl))
// && GetLastError() != SCW_E_ALREADYEXISTS)
// return false;
////Generate .rot ACL
//BYTE byRotAcl[] = {SCW_RESOURCEOPERATION_ANY, SCW_ACLTYPE_DISJUNCTIVE, 2, 1, uidRoot};
//if(!GenerateFile(WfSC_ACL_ROT, WfSC_ACL_DEFAULT, byRotAcl, sizeof(byRotAcl))
// && GetLastError() != SCW_E_ALREADYEXISTS)
// return false;
////Generate .usr ACL
//BYTE byUsrAcl[] = {SCW_RESOURCEOPERATION_ANY, SCW_ACLTYPE_DISJUNCTIVE, 4, 1, uidRoot, 1, uidUser};
//if(!GenerateFile(WfSC_ACL_USR, WfSC_ACL_DEFAULT, byUsrAcl, sizeof(byUsrAcl))
// && GetLastError() != SCW_E_ALREADYEXISTS)
// return false;
return true;
}
/*
CCard::GenerateFile
Purpose:
Generates a file with the specified contents
Params:
LPWSTR pszFileName: The file to generate
LPWSTR pszAssocACL: The ACL to associate with it
BYTE* byData: The data to populate the file with
BYTE byLen: The length of that data
Returns:
bool : true if it succeeds in creating and populating the file
false otherwise, including if the file already exists
check GetLastError()
*/
bool CCard::GenerateFile(const WCHAR* pszFileName, const WCHAR * pszAssocACL, BYTE* byData, const BYTE byLen)
{
BOOL lResult = fp.GenerateFile(pszFileName,WfSC_ACL_DEFAULT,byData,byLen);
return lResult != 0;
}
/*
GetKPUIDs
Purpose:
Gets the UIDs of the root and user KPs on the card
Params:
UID& uidRoot: reference to the destination for the root UID
UID& uidUser: reference to the destination for the user UID
Returns:
bool : true if successful, false otherwise
bool CCard::GetKPUIDs(TUID& uidRoot, TUID& uidUser)
{
return true;
}*/
/*
CCard::InitContCSPDirs
Purpose:
Ensures the required directories are on the card
Params:
None
Returns:
bool : true if it succeeds, false otherwise
*/
bool CCard::GenerateKP(DWORD dwWhichKP, LPBYTE pbyPIN, BYTE byLength)
{
//Generate filename
WCHAR szFileName[MAX_BUFFER];
switch(dwWhichKP)
{
case WfSC_CSP_KP_ROOT:
wsprintf(szFileName, WfSC_KP_PATH, WfSC_ROOT_NAME);
break;
case WfSC_CSP_KP_USER:
wsprintf(szFileName, WfSC_KP_PATH, WfSC_USER_NAME);
break;
default:
return false; //Don't know how to generate that kind of KP.
}
//TODO need to create file with acl
HANDLE hFile;
hFile = fp.NewFile(szFileName);
if(!fp.IsValid(hFile))
return false;
DWORD byWritten;
BOOL lResult;
//Write the file header
//lResult = hScwWriteFile(m_hProxy, hFile, kbyKPData, sizeof(kbyKPData), &byWritten);
lResult = fp.WriteData(hFile,kbyKPData,sizeof(kbyKPData),&byWritten);
if(!lResult || byWritten != sizeof(kbyKPData))
goto err;
//Write the number of bytes in the pin
//lResult = hScwWriteFile(m_hProxy, hFile, &byLength, 1, &byWritten);
lResult = fp.WriteData(hFile,&byLength,1,&byWritten);
if(!lResult || byWritten != 1)
goto err;
//Write the PIN.
//lResult = hScwWriteFile(m_hProxy, hFile, pbyPIN, (BYTE)byLength, &byWritten);
lResult = fp.WriteData(hFile,pbyPIN,(BYTE)byLength,&byWritten);
if(!lResult || byLength != byWritten)
goto err;
//Close the file
//hScwCloseFile(m_hProxy, hFile);
CloseHandle(hFile);
return true;
err:
CloseHandle(hFile);
//hScwDeleteFile(m_hProxy, szFileName);
fp.DelFile(szFileName);
return false;
}
bool CCard::InitContCSPDirs()
{
//Should never call this function without the card being locked
//Generate the WfSC_DIR_CONT directory
BOOL lResult = fp.NewDirectory(WfSC_DIR_CONT);
if(lResult == 0)
return false;
//Generate the WfSC_DIR_CSP directory
lResult = fp.NewDirectory(WfSC_DIR_CSP);
if(0 == lResult)
return false;
return true;
}
bool CCard::CheckPIN(DWORD dwWhichKP,BYTE* pin,BYTE pinSize)
{
return fp.VerifyPIN(dwWhichKP,pin,pinSize);
// WCHAR szFileName[MAX_BUFFER];
// switch(dwWhichKP)
// {
// case WfSC_CSP_KP_ROOT:
// wsprintf(szFileName, WfSC_KP_PATH, WfSC_ROOT_NAME);
// break;
//
// case WfSC_CSP_KP_USER:
// wsprintf(szFileName, WfSC_KP_PATH, WfSC_USER_NAME);
// break;
//
// default:
// return false; //Don't know how to generate that kind of KP.
// }
// DWORD bufferSize = sizeof(kbyKPData)+12 +1;
// HANDLE hFile = fp.GetFile(szFileName);
// BYTE* oriPin = new BYTE[bufferSize];
// DWORD size;
// BOOL lResult = fp.ReadData(hFile,oriPin,bufferSize,&size);
// if(!lResult || bufferSize < size)
// return false;
// if(oriPin[2] != AUTHPROTOCOL_PIN)
// return false;
// if(oriPin[4] < 1)
// {
// SetLastError(PINRETRY_OVER);
// return false;
// }
// if(oriPin[5] != pinSize)
// {
// goto pinfail;
// }
// else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -