bool EstEidCard::changePin_internal( PinType pinType,const PinString &newPin,const PinString &oldPin,bool useUnblockCmd ) { mManager.writeLog("[%s:%d]", __FUNCTION__, __LINE__); byte cmdChangeCmd[] = {0x00,0x24,0x00}; bool doSecure = false; //mManager.beginTransaction(mConnection); if (useUnblockCmd) cmdChangeCmd[1]= 0x2C; ByteVec cmd(MAKEVECTOR(cmdChangeCmd)); cmd.push_back((byte)pinType); size_t oldPinLen,newPinLen; if (newPin.length() < 4 || oldPin.length() < 4 ) { if (!mConnection->isSecure() ) { mManager.endTransaction(mConnection); throw std::runtime_error("bad pin length"); } doSecure = true; } else { oldPinLen = oldPin.length(); newPinLen = newPin.length(); ByteVec catPins; catPins.resize(oldPinLen + newPinLen); copy(oldPin.begin(), oldPin.end(), catPins.begin()); copy(newPin.begin(), newPin.end(), catPins.begin() + oldPin.length()); cmd.push_back(LOBYTE(catPins.size())); cmd.insert(cmd.end(),catPins.begin(),catPins.end()); } try { if (doSecure) executePinChange(cmd,0,0); else execute(cmd); } catch(AuthError &ae) { mManager.endTransaction(mConnection); throw AuthError(ae); } catch(CardError &e) { mManager.endTransaction(mConnection); if (e.SW1 == 0x63) throw AuthError(e); else if (useUnblockCmd && e.SW1==0x6a && e.SW2 == 0x80 ) //unblocking, repeating old pin throw AuthError(e.SW1,e.SW2,true); else throw e; } mManager.endTransaction(mConnection); return true; }
bool EstEidCard::changePin_internal( PinType pinType,PinString newPin,PinString oldPin,bool useUnblockCmd ) { byte cmdChangeCmd[] = {0x00,0x24,0x00}; bool doSecure = false; if (useUnblockCmd) cmdChangeCmd[1]= 0x2C; ByteVec cmd(MAKEVECTOR(cmdChangeCmd)); cmd.push_back((byte)pinType); size_t oldPinLen,newPinLen; if (newPin.length() < 4 || oldPin.length() < 4 ) { if (!mConnection->isSecure() ) throw std::runtime_error("bad pin length"); // FIXME: This is probably broken on PC/SC readers and // it is not known to work on CT-API either oldPinLen = (oldPin[0] - '0') * 10 + oldPin[1] - '0'; newPinLen = (newPin[0] - '0') * 10 + newPin[1]- '0'; oldPin = PinString(oldPinLen,'0'); newPin = PinString(newPinLen,'0'); doSecure = true; } else { oldPinLen = oldPin.length(); newPinLen = newPin.length(); } ByteVec catPins; catPins.resize(oldPinLen + newPinLen); copy(oldPin.begin(), oldPin.end(), catPins.begin()); copy(newPin.begin(), newPin.end(), catPins.begin() + oldPin.length()); cmd.push_back(LOBYTE(catPins.size())); cmd.insert(cmd.end(),catPins.begin(),catPins.end()); try { if (doSecure) executePinChange(cmd,oldPinLen,newPinLen); else execute(cmd,true); } catch(AuthError &ae) { throw AuthError(ae); } catch(CardError &e) { if (e.SW1 == 0x63) throw AuthError(e); else if (useUnblockCmd && e.SW1==0x6a && e.SW2 == 0x80 ) //unblocking, repeating old pin throw AuthError(e.SW1,e.SW2,true); else throw e; } return true; }
void EstEidCardMaintainer::performGenerateNewKeys() { card.readCardID(); card.selectEF(EstEidCard::FILEID_KEYPOINTER); ByteVec keyRec = card.readRecord(1); if (keyRec.size() != 0x15) throw CardDataError("key ptr len is not 0x15"); ByteVec authPtr(keyRec.begin() + 0x09, keyRec.begin() + 0x0A); ByteVec signPtr(keyRec.begin() + 0x13, keyRec.begin() + 0x14); card.selectMF(); card.setSecEnv(3); card.selectDF(EstEidCard::FILEID_APP); card.setSecEnv(3); /*CardBase::FCI fileInfo = */card.selectEF(0x0013); card.readEF(1); }
/* Old Mozilla plugin */ std::string EsteidAPI::getCertificatesMoz() { whitelistRequired(); try { RTERROR_TO_SCRIPT( ByteVec bv = m_service->getSignCert(); X509Certificate cert(bv); std::ostringstream buf; /* Return "compatible" JSON */ buf << "({certificates:[{"; buf << "id:'" << MAGIC_ID << "',"; buf << "cert:'"; for(ByteVec::const_iterator it = bv.begin(); it!=bv.end();it++) buf << std::setfill('0') << std::setw(2) << std::hex << (short)*it; buf << "',"; buf << "CN:'" << cert.getSubjectCN() << "',"; buf << "issuerCN:'" << cert.getIssuerCN() << "',"; // JS using this old API expects the exact string "Non-Repudiation" buf << "keyUsage:'Non-Repudiation',"; buf << "validFrom: new Date(),"; // TODO: Date(YYYY,MM,DD,HH,mm,SS) buf << "validTo: new Date()}],"; // TODO: Date(YYYY,MM,DD,HH,mm,SS) buf << "returnCode:0})"; return buf.str(); // TODO: Return proper error code from plugin (when it's implemented) )} catch(...) { return "({returnCode: 12})"; } }
void EstEidCard::readPersonalData_internal(vector<string>& data,int recStart,int recEnd) { mManager.writeLog("[%s:%d]", __FUNCTION__, __LINE__); selectMF(true); selectDF(FILEID_APP,true); FCI fileInfo = selectEF(0x5044); if (fileInfo.recCount != 0x10 && fileInfo.recCount != 0x0A && fileInfo.recCount != 0x14) { throw CardDataError("personal data file does not contain 16 or 10 records"); } data.resize(min(recEnd,0x10) + 1 ); for (int i=recStart; i <= recEnd; i++) { ByteVec record; try { record = readRecord(i); } catch(...) { throw; } string& ret = data[i]; for (ByteVec::iterator c = record.begin();c!=record.end();c++) ret+= *c ; /* EstEID 3.0 has fixed length, space padded data file records. Trim from the end */ if (getCardVersion() == VER_3_0) ret.erase(std::find_if(ret.rbegin(), ret.rend(), std::not1(std::ptr_fun<int, int>(std::isspace))).base(), ret.end()); } }
void dump(std::ostream *sout,string prefix,ByteVec &cmd) { if (!sout) return; *sout << prefix; for(ByteVec::iterator it=cmd.begin();it < cmd.end(); it++ ) *sout << std::hex << std::setfill('0') << std::setw(2) << (int) *it << " "; *sout << std::endl << std::endl; }
string CTAPIManager::getReaderState(uint index) { string retval; ensureReaders(index); cPort *dri = mPorts[index]; // byte cmd[] = {0x20,INS_GETSTATUS,0x00,0x80,0x00}; //GET STATUS, CT, all ICC status // byte cmd[] = {0x20,INS_GETSTATUS,0x00,0x81,0x00}; //GET STATUS, CT, functional spec byte cmd[] = {0x20,INS_GETSTATUS,0x01,0x80,0x00}; //GET STATUS, ICC0, ICC0 status initclose _i(dri); ByteVec resp; dri->performCmd(CTDAD_CT,MAKEVECTOR(cmd),resp,mLogger); if(resp.size() != 3) { if (resp.size() == 2) //workaround for openct resp.insert(resp.begin(),0x80); else throw CTAPIError("getReaderState0",0,resp.size(),0,0); } if (resp[0] != 0x80) throw CTAPIError("getReaderState1",0,resp.size(),resp[0],0); byte statusICC0 = resp[2]; if (statusICC0 & 0x01) retval+= "PRESENT|"; else retval+= "EMPTY|"; if ((statusICC0 & 0x6) == 0x2) retval+= "UNPOWERED|"; if ((statusICC0 & 0x6) == 0x4) retval+= "INUSE|"; if (retval.length() > 0 ) retval = retval.substr(0,retval.length()-1); return retval; }
CardBase::FCI EstEidCard::parseFCI(ByteVec fci) { ByteVec tag; FCI tmp; tmp.fileID = 0; if (fci.size() < 0x0B || (fci[0] != tagFCP && fci[0] != tagFCI) || fci.size()-2 != fci[1] ) throw CardDataError("invalid fci record"); if (getCardVersion() == VER_3_0) fci = ByteVec(fci.begin()+ 4, fci.end()); else fci = ByteVec(fci.begin()+ 2, fci.end()); tag = getTag(0x83, 2, fci); if (tag.size() != 2) throw CardDataError("file name record invalid length, not two bytes"); tmp.fileID = MAKEWORD(tag[1],tag[0]); tag = getTag(0x82, 0, fci); switch (tag[0] & 0x3F) { case 0x38: //DF case 0x01: //binary if (tag.size() != 1) throw CardDataError("linear variable file descriptor not 1 bytes long"); tag = getTag(0x85,2,fci); tmp.fileLength = MAKEWORD(tag[1],tag[0]); break; case 0x02: //linear variable case 0x04: if (tag.size() != 5) throw CardDataError("linear variable file descriptor not 5 bytes long"); tmp.recMaxLen = MAKEWORD( tag[0x03], tag[0x02] ); tmp.recCount = tag[0x04]; tmp.fileLength = 0; break; default: throw CardDataError("invalid filelen record, unrecognized tag"); } return tmp; }
string CTAPIManager::getReaderName(uint index) { string retval; ensureReaders(index); cPort *dri = mPorts[index]; byte cmd[] = {0x20,INS_GETSTATUS,0x00,0x46,0x00}; initclose _i(dri); ByteVec resp; dri->performCmd(CTDAD_CT,MAKEVECTOR(cmd),resp,mLogger); if (resp[0] != 0x46) { if (resp.size() != 2) { //openCT throw CTAPIError("getReaderName",0,resp.size(),resp[0],resp[1]); } return "opensc?"; } resp.erase(resp.begin(),resp.begin()+2); retval.resize(resp.size()); copy(resp.begin(),resp.end(),retval.begin()); return retval; }
ByteVec AUTH_SESSION::ParmEncrypt(ByteVec& parm, bool directionCommand) { ByteVec nonceNewer, nonceOlder; if (directionCommand) { nonceNewer = NonceCaller; nonceOlder = NonceTpm; } else { nonceNewer = NonceTpm; nonceOlder = NonceCaller; } if (Symmetric.algorithm != TPM_ALG_ID::AES) { throw domain_error("Only AES parm encryption is implemtented"); } if (Symmetric.keyBits != 128) { throw domain_error("Only AES-128 parm encryption is implemtented"); } if (Symmetric.mode != TPM_ALG_ID::CFB) { throw domain_error("Only AES-128-CFB parm encryption is implemtented"); } int numKdfBits = 256; int numBits = 128; ByteVec encKey = SessionKey; ByteVec keyInfo = KDF::KDFa(HashAlg, encKey, "CFB", nonceNewer, nonceOlder, numKdfBits); size_t keySize = numBits / 8; ByteVec key(keyInfo.begin(), keyInfo.begin() + keySize); ByteVec iv(keyInfo.begin() + keySize, keyInfo.end()); ByteVec xcrypted = CryptoServices::CFBXncrypt(directionCommand, TPM_ALG_ID::AES, key, iv, parm); return xcrypted; }
ByteVec EstEidCard::calcSign_internal(AlgType type,KeyType keyId,ByteVec hash,bool withOID) { byte signCmdSig[] = {0x00,0x2A,0x9E,0x9A}; byte signCmdAut[] = {0x00,0x88,0x00,0x00}; byte hashHdMD5[] = {0x30,0x20,0x30,0x0C,0x06,0x08,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x02,0x05,0x05,0x00,0x04,0x10}; byte hashHdSHA1[] = {0x30,0x21,0x30,0x09,0x06,0x05,0x2B,0x0E,0x03,0x02,0x1A,0x05,0x00,0x04,0x14}; ByteVec cmd,header; if (keyId == 0 ) cmd = MAKEVECTOR(signCmdAut); else cmd = MAKEVECTOR(signCmdSig); if (withOID) { switch(type) { case MD5: header = MAKEVECTOR(hashHdMD5); break; case SHA1: header = MAKEVECTOR(hashHdSHA1); break; default: throw std::runtime_error("cannot calculate SSL signature with OID"); } cmd.push_back((byte) (header.size() + hash.size())); cmd.insert(cmd.end(), header.begin(), header.end()); } else cmd.push_back((byte)hash.size()); setSecEnv(1); cmd.insert(cmd.end(), hash.begin(), hash.end()); ByteVec result; try { result = execute(cmd); } catch(CardError e) { if (e.SW1 == 0x69 && (e.SW2 == 0x82 || e.SW2 == 0x00 || e.SW2 == 0x85 )) throw AuthError(e); throw e; } return result; }
MojErr MojDbLevelQuery::seekImpl(const ByteVec& key, bool desc, bool& foundOut) { if (key.empty()) { // if key is empty, seek to beginning (or end if desc) MojErr err = getKey(foundOut, SeekEmptyFlags[desc]); MojErrCheck(err); } else { // otherwise seek to the key MojErr err = m_key.fromBytes(key.begin(), key.size()); MojErrCheck(err); err = getKey(foundOut, SeekFlags); MojErrCheck(err); // if descending, skip the first result (which is outside the range) if (desc) { err = next(foundOut); MojErrCheck(err); } } return MojErrNone; }
ByteVec EstEidCard::RSADecrypt_internal(ByteVec cipher) { byte modEnv1[] = {0x00,0x22,0x41,0xA4,0x02,0x83,0x00}; byte modEnv2[] = {0x00,0x22,0x41,0xB6,0x02,0x83,0x00}; byte modEnv0[] = {0x00,0x22,0x41,0xB8,0x05,0x83,0x03,0x80}; selectMF(true); selectDF(FILEID_APP,true); selectEF(FILEID_KEYPOINTER,true); ByteVec keyRec = readRecord(1); if (keyRec.size() != 0x15) throw CardDataError("key ptr len is not 0x15"); ByteVec cmd(MAKEVECTOR(modEnv0)); cmd.insert(cmd.end(),&keyRec[0x9],&keyRec[0xB]); setSecEnv(6); execute(MAKEVECTOR(modEnv1),true); execute(MAKEVECTOR(modEnv2),true); execute(cmd,true); byte decrpt[] = {0x00,0x2A,0x80,0x86,0x81,0x00}; ByteVec decCmd(MAKEVECTOR(decrpt)); decCmd.insert(decCmd.end(),cipher.begin(),cipher.end()); ByteVec result; try { result = execute(decCmd,false); } catch(CardError e) { /* if (e.SW1 == 0x69 && e.SW2 == 0x88 ) { reverse(decCmd.begin() + 6, decCmd.end()); result = execute(decCmd,false); return result; }*/ if (e.SW1 == 0x69 && (e.SW2 == 0x82 || e.SW2 == 0x00 || e.SW2 == 0x88 || e.SW2 == 0x85 /*|| e.SW1 == 0x64 */|| e.SW1 == 0x6B )) throw AuthError(e); throw e; } return result; }
int MojDbIsamQuery::compareKey(const ByteVec& key) { return MojLexicalCompare(m_keyData, m_keySize, key.begin(), key.size()); }
// Called within a transaction ByteVec EstEidCard::RSADecrypt_internal(const ByteVec &cryptogram) { mManager.writeLog("[%s:%d]", __FUNCTION__, __LINE__); if (_card_version == VER_3_0 && cryptogram.size() != 256) throw std::runtime_error("2048 bit keys but cryptogram is not 256 bytes!"); if (_card_version != VER_3_0 && cryptogram.size() != 128) throw std::runtime_error("cryptogram is not 128 bytes!"); byte modEnv1[] = {0x00,0x22,0x41,0xA4,0x02,0x83,0x00}; byte modEnv2[] = {0x00,0x22,0x41,0xB6,0x02,0x83,0x00}; byte modEnv0[] = {0x00,0x22,0x41,0xB8,0x05,0x83,0x03,0x80}; //mManager.beginTransaction(mConnection); selectMF(true); selectDF(FILEID_APP,true); selectEF(FILEID_KEYPOINTER,true); ByteVec keyRec = readRecord(1); if (keyRec.size() != 0x15) { mManager.endTransaction(mConnection); throw CardDataError("key ptr len is not 0x15"); } ByteVec cmd(MAKEVECTOR(modEnv0)); cmd.insert(cmd.end(),&keyRec[0x9],&keyRec[0xB]); setSecEnv(6); execute(MAKEVECTOR(modEnv1)); execute(MAKEVECTOR(modEnv2)); execute(cmd); ByteVec result; try { if (_card_version == VER_3_0) { // Use chaining for decryption byte decrypt_chain1[] = {0x10, 0x2A, 0x80, 0x86, 0xFF, 0x00}; byte decrypt_chain2[] = {0x00, 0x2A, 0x80, 0x86, 0x02}; ByteVec first_command(MAKEVECTOR(decrypt_chain1)); ByteVec second_command(MAKEVECTOR(decrypt_chain2)); first_command.insert(first_command.end(), cryptogram.begin(), cryptogram.end()-2); second_command.insert(second_command.end(), cryptogram.end()-2, cryptogram.end()); execute(first_command, 2); result = execute(second_command, 4); } else { byte decrypt[] = {0x00, 0x2A, 0x80, 0x86, 0x81, 0x00}; ByteVec decrypt_command(MAKEVECTOR(decrypt)); decrypt_command.insert(decrypt_command.end(), cryptogram.begin(), cryptogram.end()); result = execute(decrypt_command, 4); } } catch(CardError e) { mManager.endTransaction(mConnection); if (e.SW1 == 0x69 && (e.SW2 == 0x82 || e.SW2 == 0x00 || e.SW2 == 0x88 || e.SW2 == 0x85 /*|| e.SW1 == 0x64 */|| e.SW1 == 0x6B )) throw AuthError(e); throw e; } mManager.endTransaction(mConnection); return result; }
ByteVec EstEidCard::calcSign_internal(AlgType type,KeyType keyId,const ByteVec &hash,bool withOID) { mManager.writeLog("[%s:%d]", __FUNCTION__, __LINE__); byte signCmdSig[] = {0x00,0x2A,0x9E,0x9A}; byte signCmdAut[] = {0x00,0x88,0x00,0x00}; byte hashHdMD5[] = {0x30,0x20,0x30,0x0C,0x06,0x08,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x02,0x05,0x05,0x00,0x04,0x10}; byte hashHdSHA1[] = {0x30,0x21,0x30,0x09,0x06,0x05,0x2B,0x0E,0x03,0x02,0x1A,0x05,0x00,0x04,0x14}; byte hashHdSHA224[] = {0x30,0x2d,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x04,0x05,0x00,0x04,0x1c}; byte hashHdSHA256[] = {0x30,0x31,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x01,0x05,0x00,0x04,0x20}; byte hashHdSHA384[] = {0x30,0x41,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x02,0x05,0x00,0x04,0x30}; byte hashHdSHA512[] = {0x30,0x51,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x03,0x05,0x00,0x04,0x40}; ByteVec cmd,header; if (keyId == 0 ) { cmd = MAKEVECTOR(signCmdAut); } else { cmd = MAKEVECTOR(signCmdSig); } if (withOID) { switch(type) { case MD5: header = MAKEVECTOR(hashHdMD5); break; case SHA1: header = MAKEVECTOR(hashHdSHA1); break; case SHA224: header = MAKEVECTOR(hashHdSHA224); break; case SHA256: header = MAKEVECTOR(hashHdSHA256); break; case SHA384: header = MAKEVECTOR(hashHdSHA384); break; case SHA512: header = MAKEVECTOR(hashHdSHA512); break; default: throw std::runtime_error("cannot calculate SSL signature with OID"); } cmd.push_back((byte) (header.size() + hash.size())); cmd.insert(cmd.end(), header.begin(), header.end()); } else cmd.push_back((byte)hash.size()); setSecEnv(1); cmd.insert(cmd.end(), hash.begin(), hash.end()); ByteVec result; try { //#ifdef _WIN32 //setVersion();//SIGSEGs Under Linux. Needed only for Windows MiniDriver //#endif if(_card_version != VER_3_0) { mManager.writeLog("[%s:%d] Sending APDU case 4 (Card version %i)", __FUNCTION__, __LINE__, getCardVersion()); result = execute(cmd, 4); } else { mManager.writeLog("[%s:%d] Sending default APDU case (Card version %i)", __FUNCTION__, __LINE__, getCardVersion()); result = execute(cmd); } } catch(CardError e) { if (e.SW1 == 0x69 && (e.SW2 == 0x82 || e.SW2 == 0x00 || e.SW2 == 0x85 )) throw AuthError(e); throw e; } return result; }