Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

620 lines
14 KiB

// V1Card.cpp: implementation of the CV2Card class.
//
// (c) Copyright Schlumberger Technology Corp., unpublished work, created
// 1999. This computer program includes Confidential, Proprietary
// Information and is a Trade Secret of Schlumberger Technology Corp. All
// use, disclosure, and/or reproduction is prohibited unless authorized
// in writing. All Rights Reserved.
//////////////////////////////////////////////////////////////////////
#include "NoWarning.h"
#include <algorithm>
#include <functional>
#include <memory> // for auto_ptr
#include <scuArrayP.h>
#include <SmartCard.h>
#include "TransactionWrap.h"
#include "cciExc.h"
#include "MethodHelp.h"
#include "cciCert.h"
#include "cciKeyPair.h"
#include "cciPriKey.h"
#include "cciPubKey.h"
#include "V1Cert.h"
#include "V1Cont.h"
#include "V1ContRec.h"
#include "V1KeyPair.h"
#include "V1PriKey.h"
#include "V1PubKey.h"
#include "V1Paths.h"
#include "V1Card.h"
using namespace std;
using namespace cci;
/////////////////////////// LOCAL/HELPER /////////////////////////////////
namespace
{
// Enumerate T type objects in the exchange and signature key pair
// using C::<Accessor> to get the T object, returning vector<T>
// objects.
template<class T>
class EnumItems
: std::unary_function<void, vector<T> >
{
public:
EnumItems(CV1Card const &rv1card,
ObjectAccess oa,
AccessorMethod<T, CAbstractKeyPair>::AccessorPtr Accessor)
: m_rv1card(rv1card),
m_oa(oa),
m_matAccess(Accessor),
m_Result()
{}
result_type
operator()(argument_type)
{
DoAppend(m_rv1card.DefaultContainer());
return m_Result;
}
protected:
void
DoAppend(CContainer &rhcntr)
{
if (rhcntr)
{
AppendItem(rhcntr->ExchangeKeyPair());
AppendItem(rhcntr->SignatureKeyPair());
}
}
private:
void
AppendItem(CKeyPair &rhkp)
{
if (rhkp)
{
T hObject(m_matAccess(*rhkp));
if (hObject && (m_oa == hObject->Access()))
m_Result.push_back(hObject);
}
}
CV1Card const &m_rv1card;
ObjectAccess m_oa;
MemberAccessorType<T, CAbstractKeyPair> m_matAccess;
result_type m_Result;
};
bool
IsSupported(iop::CSmartCard &rSmartCard) throw()
{
bool fSupported = false;
try
{
rSmartCard.Select(CV1Paths::Chv());
rSmartCard.Select(CV1Paths::IcFile());
rSmartCard.Select(CV1Paths::RootContainers());
rSmartCard.Select(CV1Paths::PrivateKeys());
rSmartCard.Select(CV1Paths::PublicKeys());
fSupported = true;
}
catch(scu::Exception &)
{}
return fSupported;
}
} // namespace
/////////////////////////// PUBLIC /////////////////////////////////
// Types
// C'tors/D'tors
CV1Card::~CV1Card() throw()
{}
// Operators
// Operations
void
CV1Card::CardId(string const &rsNewCardId) const
{
CTransactionWrap(this);
DWORD dwLen = OpenFile(CV1Paths::IcFile());
if (0 == dwLen)
throw scu::OsException(NTE_FAIL);
if (rsNewCardId.length() > dwLen)
throw scu::OsException(ERROR_INVALID_PARAMETER);
if (rsNewCardId.length() < dwLen)
SmartCard().WriteBinary(0, rsNewCardId.length() + 1,
reinterpret_cast<BYTE const *>(rsNewCardId.c_str()));
else
SmartCard().WriteBinary(0,
static_cast<WORD>(rsNewCardId.length()),
reinterpret_cast<BYTE const *>(rsNewCardId.data()));
RefreshCardId();
}
void
CV1Card::ChangePIN(string const &rstrOldPIN,
string const &rstrNewPIN)
{
CTransactionWrap wrap(this);
SmartCard().Select(CV1Paths::Root());
SuperClass::ChangePIN(rstrOldPIN, rstrNewPIN);
}
void
CV1Card::DefaultContainer(CContainer const &rcont)
{
m_avhDefaultCntr.Value(rcont);
if(!m_avhDefaultCntr.Value())
m_avhDefaultCntr.Dirty();
// Nothing more to do since, by definition, the one and only
// container is already the default container.
}
pair<string, // interpreted as the public modulus
CPrivateKey>
CV1Card::GenerateKeyPair(KeyType kt,
string const &rsExponent,
ObjectAccess oaPrivateKey)
{
throw Exception(ccNotImplemented);
return pair<string, CPrivateKey>();
}
void
CV1Card::InitCard()
{
// We want to select /3f00/0015 (length 1744) and /3f00/3f11/0015 (length 300), and clear both files.
CTransactionWrap wrap(this);
BYTE bData[1744];
memset(bData, 0, 1744);
SmartCard().Select(CV1Paths::RootContainers());
SmartCard().WriteBinary(0x0000, 0x06d0, bData);
SmartCard().Select(CV1Paths::PublicKeys());
SmartCard().WriteBinary(0x0000, 0x012c, bData);
}
void
CV1Card::InvalidateCache()
{
m_avhDefaultCntr.Value(CContainer());
m_avhDefaultCntr.Dirty();
m_avhExchangeKeyPair.Value(CKeyPair());
m_avhExchangeKeyPair.Dirty();
m_avhSignatureKeyPair.Value(CKeyPair());
m_avhSignatureKeyPair.Dirty();
}
void
CV1Card::Label(string const &rLabel)
{
throw Exception(ccNotImplemented);
}
DWORD
CV1Card::OpenFile(char const *szPath) const
{
iop::FILE_HEADER fh;
SmartCard().Select(szPath, &fh);
return fh.file_size;
}
void
CV1Card::VerifyKey(string const &rstrKey,
BYTE bKeyNum)
{
CTransactionWrap wrap(this);
SmartCard().Select(CV1Paths::CryptoSys());
SuperClass::VerifyKey(rstrKey, bKeyNum);
}
// Access
size_t
CV1Card::AvailableStringSpace(ObjectAccess oa) const
{
throw Exception(ccNotImplemented);
return 0;
}
string
CV1Card::CardId() const
{
return m_sCardId;
}
CContainer
CV1Card::DefaultContainer() const
{
CTransactionWrap wrap(this);
if (!m_avhDefaultCntr.IsCached())
{
auto_ptr<CV1Container> apv1cntr(new CV1Container(*this,
CV1ContainerRecord::DefaultName(),
false));
if (apv1cntr->Exists())
{
CContainer hcntr;
hcntr = CContainer(apv1cntr.get());
apv1cntr.release();
m_avhDefaultCntr.Value(hcntr);
}
}
return m_avhDefaultCntr.Value();
}
vector<CContainer>
CV1Card::EnumContainers() const
{
CContainer hcntr(0);
auto_ptr<CV1Container> apv1cntr(new CV1Container(*this,
CV1ContainerRecord::DefaultName(),
false));
if (apv1cntr->Exists())
{
hcntr = CContainer(apv1cntr.get());
apv1cntr.release();
}
vector<CContainer> vhcntr;
if (hcntr)
vhcntr.push_back(hcntr);
return vhcntr;
}
vector<CCertificate>
CV1Card::EnumCertificates(ObjectAccess access) const
{
CTransactionWrap wrap(this);
EnumItems<CCertificate> Enumerator(*this, access,
CAbstractKeyPair::Certificate);
return Enumerator();
}
vector<CPublicKey>
CV1Card::EnumPublicKeys(ObjectAccess access) const
{
CTransactionWrap wrap(this);
EnumItems<CPublicKey> Enumerator(*this, access,
CAbstractKeyPair::PublicKey);
return Enumerator();
}
vector<CPrivateKey>
CV1Card::EnumPrivateKeys(ObjectAccess access) const
{
CTransactionWrap wrap(this);
EnumItems<CPrivateKey> Enumerator(*this, access,
CAbstractKeyPair::PrivateKey);
return Enumerator();
}
vector<CDataObject>
CV1Card::EnumDataObjects(ObjectAccess access) const
{
return vector<CDataObject>(); // can never have data objects
}
string
CV1Card::Label() const
{
throw Exception(ccNotImplemented);
return string();
}
CAbstractCertificate *
CV1Card::MakeCertificate(ObjectAccess oa) const
{
CTransactionWrap wrap(this);
if (oaPublicAccess != oa)
throw Exception(ccInvalidParameter);
return new CV1Certificate(*this, ksNone);
}
CAbstractContainer *
CV1Card::MakeContainer() const
{
CTransactionWrap wrap(this);
return new CV1Container(*this,
CV1ContainerRecord::DefaultName(), true);
}
CAbstractDataObject *
CV1Card::MakeDataObject(ObjectAccess oa) const
{
throw Exception(ccNotImplemented);
return 0;
}
CAbstractKeyPair *
CV1Card::MakeKeyPair(CContainer const &rhcont,
KeySpec ks) const
{
CTransactionWrap wrap(this);
// If the key pair is cached, return it; otherwise make a new one
// and cache it.
CArchivedValue<CKeyPair> *pavhkp = 0;
switch (ks)
{
case ksExchange:
pavhkp = &m_avhExchangeKeyPair;
break;
case ksSignature:
pavhkp = &m_avhSignatureKeyPair;
break;
default:
throw Exception(ccBadKeySpec);
break;
}
if (!pavhkp->IsCached() || !pavhkp->Value())
pavhkp->Value(CKeyPair(new CV1KeyPair(*this, rhcont, ks)));
return pavhkp->Value().operator->(); // yuk!
}
CAbstractPrivateKey *
CV1Card::MakePrivateKey(ObjectAccess oa) const
{
CTransactionWrap wrap(this);
if (oaPrivateAccess != oa)
throw Exception(ccInvalidParameter);
return new CV1PrivateKey(*this, ksNone);
}
CAbstractPublicKey *
CV1Card::MakePublicKey(ObjectAccess oa) const
{
CTransactionWrap wrap(this);
if (oaPublicAccess != oa)
throw Exception(ccInvalidParameter);
return new CV1PublicKey(*this, ksNone);
}
BYTE
CV1Card::MaxKeys(KeyType kt) const
{
BYTE bCount;
switch (kt)
{
case ktRSA1024:
bCount = 2;
break;
default:
bCount = 0;
break;
}
return bCount;
}
size_t
CV1Card::MaxStringSpace(ObjectAccess oa) const
{
throw Exception(ccNotImplemented);
return 0;
}
bool
CV1Card::SupportedKeyFunction(KeyType kt,
CardOperation oper) const
{
bool fSupported = false;
switch (oper)
{
case coEncryption: // .. or public key operations
break;
case coDecryption: // .. or private key operations
switch (kt)
{
case ktRSA1024:
fSupported = true;
break;
default:
break;
}
default:
break;
}
return fSupported;
}
// Predicates
bool
CV1Card::IsCAPIEnabled() const
{
return true;
}
bool
CV1Card::IsPKCS11Enabled() const
{
return false;
}
bool
CV1Card::IsProtectedMode() const
{
return true;
}
bool
CV1Card::IsKeyGenEnabled() const
{
return false;
}
bool
CV1Card::IsEntrustEnabled() const
{
return false;
}
BYTE
CV1Card::MajorVersion() const
{
return (BYTE)0;
}
// Static Variables
/////////////////////////// PROTECTED /////////////////////////////////
// C'tors/D'tors
CV1Card::CV1Card(string const &rstrReaderName,
auto_ptr<iop::CIOP> &rapiop,
auto_ptr<iop::CSmartCard> &rapSmartCard)
: SuperClass(rstrReaderName, rapiop, rapSmartCard),
m_sCardId(),
m_avhDefaultCntr(),
m_avhExchangeKeyPair(),
m_avhSignatureKeyPair()
{}
// Operators
// Operations
void
CV1Card::DoSetup()
{
CAbstractCard::DoSetup();
RefreshCardId();
}
// Access
// Predicates
// Static Variables
/////////////////////////// PRIVATE /////////////////////////////////
// C'tors/D'tors
// Operators
// Operations
auto_ptr<CAbstractCard>
CV1Card::DoMake(string const &rstrReaderName,
auto_ptr<iop::CIOP> &rapiop,
auto_ptr<iop::CSmartCard> &rapSmartCard)
{
return IsSupported(*rapSmartCard.get())
? auto_ptr<CAbstractCard>(new CV1Card(rstrReaderName, rapiop,
rapSmartCard))
: auto_ptr<CAbstractCard>(0);
}
string
CV1Card::ReadCardId() const
{
string sCardId;
// *** BEGIN WORKAROUND ***
// The following SetContext and OpenFile call is made to
// make sure the card and this system's current path are
// synchronized, pointing to the right directory. Without
// it, the subsequent call to ReadBinaryFile fails because
// they appear to be out of synch. It's not clear why
// this happens but this workaround avoids the problem.
try
{
SmartCard().Select(CV1Paths::RootContainers());
}
catch (...)
{
}
// *** END WORKAROUND ***
try
{
iop::FILE_HEADER fh;
SmartCard().Select(CV1Paths::IcFile(), &fh);
DWORD dwLen = fh.file_size;
scu::AutoArrayPtr<BYTE> aaCardId(new BYTE[dwLen + 1]);
SmartCard().ReadBinary(0, dwLen, aaCardId.Get());
aaCardId[dwLen] = '\0';
sCardId.assign(reinterpret_cast<char *>(aaCardId.Get()));
}
catch (...)
{
}
return sCardId;
}
void
CV1Card::RefreshCardId() const
{
m_sCardId = ReadCardId();
}
// Access
// Predicates
// Static Variables