// V2Card.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 #include "TransactionWrap.h" #include "V2Card.h" #include "V2Cert.h" #include "V2Cont.h" #include "V2PriKey.h" #include "V2PubKey.h" #include "V2KeyPair.h" #include "V2DataObj.h" using namespace std; using namespace cci; using namespace scu; /////////////////////////// LOCAL/HELPER ///////////////////////////////// namespace { // Functors to make a T for a given symbol id (handle/symbol id) template class MakerFunction { public: typedef T ValueType; virtual ~MakerFunction() throw() {} virtual auto_ptr operator()(SymbolID sid) const = 0; protected: MakerFunction(CV2Card const &rv2card) : m_rv2card(rv2card) {} CV2Card const &m_rv2card; }; template class Maker2 : public MakerFunction { public: Maker2(CV2Card const &rv2card) : MakerFunction(rv2card) {} auto_ptr operator()(SymbolID sid) const { return auto_ptr(new T(m_rv2card, sid)); } }; template class Maker3 : public MakerFunction { public: Maker3(CV2Card const &rv2card, ObjectAccess oa) : MakerFunction(rv2card), m_oa(oa) {} auto_ptr operator()(SymbolID sid) const { return auto_ptr(new T(m_rv2card, sid, m_oa)); } private: ObjectAccess m_oa; }; // Enumerate objects in the object info file of object type OT, // returning a vector of R(object) template vector EnumPriviledgedObjects(CObjectInfoFile &rObjInfo, MakerFunction &rMaker) { SymbolID sid = rObjInfo.FirstObject(OT); vector vResult; while (sid) { auto_ptr::ValueType> apObject(rMaker(sid)); R Handle(apObject.get()); apObject.release(); // transfer ownership to handle vResult.push_back(Handle); sid = rObjInfo.NextObject(sid); } return vResult; } bool IsSupported(iop::CSmartCard &rSmartCard) throw() { bool fSupported = false; try { rSmartCard.Select("/3f00/0000"); rSmartCard.Select("/3f00/3f11/0020"); rSmartCard.Select("/3f00/3f11/0030"); rSmartCard.Select("/3f00/3f11/0031"); fSupported = true; } catch(scu::Exception &) {} return fSupported; } } // namespace /////////////////////////// PUBLIC ///////////////////////////////// // Types // C'tors/D'tors CV2Card::~CV2Card() throw() {} // Operators // Operations void CV2Card::ChangePIN(SecureArray const &rstrOldPIN, SecureArray const &rstrNewPIN) { CTransactionWrap wrap(this); SmartCard().Select(RootPath().c_str()); SuperClass::ChangePIN(rstrOldPIN, rstrNewPIN); } void CV2Card::DefaultContainer(CContainer const &rcont) { SymbolID sid = 0; if (rcont) { CV2Container &rv2cont = scu::DownCast(*rcont); sid = rv2cont.Handle(); } ObjectInfoFile(oaPublicAccess).DefaultContainer(sid); } pair CV2Card::GenerateKeyPair(KeyType kt, string const &rsExponent, ObjectAccess oaPrivateKey) { CTransactionWrap wrap(this); // For the time being, assume this is implict RSA only.... string::size_type const cExponentLength = rsExponent.size(); if ((cExponentLength < 1) || (cExponentLength > 4)) throw Exception(ccInvalidParameter); BYTE bKeyType; switch (kt) { case ktRSA512: bKeyType = CardKeyTypeRSA512; break; case ktRSA768: bKeyType = CardKeyTypeRSA768; break; case ktRSA1024: bKeyType = CardKeyTypeRSA1024; break; default: throw Exception(ccBadKeySpec); break; } // Allocated a slot in the key file, unless a correct one is // already allocated? CCardInfo &rci = this->CardInfo(); BYTE bKeyNum = rci.AllocatePrivateKey(bKeyType); // Generate private key this->SmartCard().Select(PrivateKeyPath(kt).c_str()); iop::CPublicKeyBlob pubkb(this->SmartCard().GenerateKeyPair(reinterpret_cast(rsExponent.data()), static_cast(cExponentLength), bKeyNum, kt)); this->SmartCard().Select(RootPath().c_str()); auto_ptr apv2prikey(new CV2PrivateKey(*this, bKeyType, bKeyNum, oaPrivateKey)); string sModulus(reinterpret_cast(pubkb.bModulus), pubkb.bModulusLength); return pair(sModulus, apv2prikey.release()); } void CV2Card::InitCard() { CTransactionWrap wrap(this); m_apCardInfo->Reset(); ObjectInfoFile(oaPublicAccess).Reset(); ObjectInfoFile(oaPrivateAccess).Reset(); } void CV2Card::InvalidateCache() { CTransactionWrap wrap(this); m_apCardInfo->UpdateCache(); m_asLabel.Dirty(); m_apPublicObjectInfoFile = auto_ptr(0); m_apPrivateObjectInfoFile = auto_ptr(0); } void CV2Card::Label(string const &rLabel) { CTransactionWrap wrap(this); m_apCardInfo->Label(rLabel); m_asLabel.Value(rLabel); } void CV2Card::VerifyKey(string const &rstrKey, BYTE bKeyNum) { CTransactionWrap wrap(this); SmartCard().Select(RootPath().c_str()); SuperClass::VerifyKey(rstrKey, bKeyNum); } // Access size_t CV2Card::AvailableStringSpace(ObjectAccess oa) const { CTransactionWrap wrap(this); return ObjectInfoFile(oa).FreeSpace(); } CCardInfo & CV2Card::CardInfo() const { return *m_apCardInfo; } CContainer CV2Card::DefaultContainer() const { CTransactionWrap wrap(this); SymbolID sid = ObjectInfoFile(oaPublicAccess).DefaultContainer(); return sid ? CContainer(CV2Container::Make(*this, sid)) : CContainer(); } vector CV2Card::EnumContainers() const { CTransactionWrap wrap(this); Maker2 Maker(*this); return EnumPriviledgedObjects(ObjectInfoFile(oaPublicAccess), Maker); } vector CV2Card::EnumCertificates(ObjectAccess access) const { CTransactionWrap wrap(this); Maker3 Maker(*this, access); return EnumPriviledgedObjects(ObjectInfoFile(access), Maker); } vector CV2Card::EnumPublicKeys(ObjectAccess access) const { CTransactionWrap wrap(this); Maker3 Maker(*this, access); return EnumPriviledgedObjects(ObjectInfoFile(access), Maker); } vector CV2Card::EnumPrivateKeys(ObjectAccess access) const { CTransactionWrap wrap(this); Maker3 Maker(*this, access); return EnumPriviledgedObjects(ObjectInfoFile(access), Maker); } vector CV2Card::EnumDataObjects(ObjectAccess access) const { CTransactionWrap wrap(this); Maker3 Maker(*this, access); return EnumPriviledgedObjects(ObjectInfoFile(access), Maker); } string CV2Card::Label() const { CTransactionWrap wrap(this); if (!m_asLabel.IsCached()) m_asLabel.Value(m_apCardInfo->Label()); return m_asLabel.Value(); } CAbstractCertificate * CV2Card::MakeCertificate(ObjectAccess oa) const { CTransactionWrap wrap(this); return new CV2Certificate(*this, oa); } CAbstractContainer * CV2Card::MakeContainer() const { CTransactionWrap wrap(this); return new CV2Container(*this); } CAbstractDataObject * CV2Card::MakeDataObject(ObjectAccess oa) const { CTransactionWrap wrap(this); return new CV2DataObject(*this, oa); } CAbstractKeyPair * CV2Card::MakeKeyPair(CContainer const &rhcont, KeySpec ks) const { CTransactionWrap wrap(this); return new CV2KeyPair(*this, rhcont, ks); } CAbstractPrivateKey * CV2Card::MakePrivateKey(ObjectAccess oa) const { CTransactionWrap wrap(this); return new CV2PrivateKey(*this, oa); } CAbstractPublicKey * CV2Card::MakePublicKey(ObjectAccess oa) const { CTransactionWrap wrap(this); return new CV2PublicKey(*this, oa); } BYTE CV2Card::MaxKeys(KeyType kt) const { BYTE bCount; switch (kt) { case ktRSA512: bCount = m_apCardInfo->NumRSA512Keys(); break; case ktRSA768: bCount = m_apCardInfo->NumRSA768Keys(); break; case ktRSA1024: bCount = m_apCardInfo->NumRSA1024Keys(); break; default: bCount = 0; break; } return bCount; } size_t CV2Card::MaxStringSpace(ObjectAccess oa) const { return ObjectInfoFile(oa).TableSize(); } string CV2Card::PrivateKeyPath(KeyType kt) const { string sPrivateKeyPath(RootPath()); switch (kt) { case ktRSA512: sPrivateKeyPath += "3f01"; break; case ktRSA768: sPrivateKeyPath += "3f02"; break; case ktRSA1024: sPrivateKeyPath += "3f03"; break; default: throw Exception(ccBadKeySpec); break; } return sPrivateKeyPath; } string const & CV2Card::RootPath() const { static string const sRootPath("/3f00/3f11/"); return sRootPath; } bool CV2Card::SupportedKeyFunction(KeyType kt, CardOperation oper) const { bool fSupported = false; switch (oper) { case coEncryption: // .. or public key operations switch (kt) { case ktRSA512: case ktRSA768: case ktRSA1024: fSupported = false; break; default: fSupported = false; break; } case coDecryption: // .. or private key operations switch (kt) { case ktRSA512: case ktRSA768: case ktRSA1024: fSupported = true; break; default: fSupported = false; break; } case coKeyGeneration: switch (kt) { case ktRSA512: case ktRSA768: case ktRSA1024: { BYTE flag = m_apCardInfo->UsagePolicy(); fSupported = BitSet(&flag, CardKeyGenSupportedFlag); break; } default: break; } default: break; } return fSupported; } scu::Marker CV2Card::MarkerOnCard() const { // Security: in order to avoid using the insecure mapped file // object we use a marker on the card. This reduces efficiency but // improves security. We use the last 4 butes (RFU) from the // object info file of the 0030 file. The 0030 file is readable // but write protected by the user pin. WORD wOffset = 6;// the last 4 out of 10 bytes will be used unsigned int nMarker = 0; const WORD wBufLength = 4; CTransactionWrap wrap(this); this->SmartCard().Select("/3f00/3f11/0030"); this->SmartCard().ReadBinary(wOffset, wBufLength, (BYTE*)&nMarker); if(this->SmartCard().Dirty()) { // Information was written to the card. Update the marker nMarker++; this->SmartCard().WriteBinary(wOffset, wBufLength, (BYTE*)&nMarker); } return scu::Marker(nMarker); } // Predicates bool CV2Card::IsCAPIEnabled() const { BYTE flag = m_apCardInfo->UsagePolicy(); return BitSet(&flag,CardCryptoAPIEnabledFlag); } bool CV2Card::IsPKCS11Enabled() const { BYTE flag = m_apCardInfo->UsagePolicy(); return BitSet(&flag,CardPKCS11EnabledFlag); } bool CV2Card::IsProtectedMode() const { BYTE flag = m_apCardInfo->UsagePolicy(); return BitSet(&flag,CardProtectedWriteFlag); } bool CV2Card::IsKeyGenEnabled() const { BYTE flag = m_apCardInfo->UsagePolicy(); return BitSet(&flag,CardKeyGenSupportedFlag); } bool CV2Card::IsEntrustEnabled() const { BYTE flag = m_apCardInfo->UsagePolicy(); return BitSet(&flag,CardEntrustEnabledFlag); } BYTE CV2Card::MajorVersion() const { return m_apCardInfo->FormatVersion().bMajor; } bool CV2Card::IsMarkerOnCard() const { return true; } // Static Variables /////////////////////////// PROTECTED ///////////////////////////////// // C'tors/D'tors CV2Card::CV2Card(string const &rstrReaderName, auto_ptr &rapiop, auto_ptr &rapSmartCard) : SuperClass(rstrReaderName, rapiop, rapSmartCard), m_apCardInfo(auto_ptr(new CCardInfo(*rapSmartCard.get()))), m_apPublicObjectInfoFile(), m_apPrivateObjectInfoFile(), m_asLabel() {} // Operators // Operations void CV2Card::DoSetup() { CAbstractCard::DoSetup(); m_apCardInfo->UpdateCache(); } // Access // Predicates // Static Variables /////////////////////////// PRIVATE ///////////////////////////////// // C'tors/D'tors // Operators // Operations auto_ptr CV2Card::DoMake(string const &rstrReaderName, auto_ptr &rapiop, auto_ptr &rapSmartCard) { return IsSupported(*rapSmartCard.get()) ? auto_ptr(new CV2Card(rstrReaderName, rapiop, rapSmartCard)) : auto_ptr(0); } // Access CObjectInfoFile & CV2Card::ObjectInfoFile(ObjectAccess oa) const { CObjectInfoFile *poif; switch (oa) { case oaPublicAccess: if (!m_apPublicObjectInfoFile.get()) { m_apPublicObjectInfoFile = auto_ptr(new CObjectInfoFile(SmartCard(), "/3f00/3f11/0030", oa)); m_apPublicObjectInfoFile->UpdateCache(); } poif = m_apPublicObjectInfoFile.get(); break; case oaPrivateAccess: if (!m_apPrivateObjectInfoFile.get()) { m_apPrivateObjectInfoFile = auto_ptr(new CObjectInfoFile(SmartCard(), "/3f00/3f11/0031", oa)); m_apPrivateObjectInfoFile->UpdateCache(); } poif = m_apPrivateObjectInfoFile.get(); break; default: throw Exception(ccBadAccessSpec); } return *poif; } // Predicates // Static Variables