preparations for writing a file; refs #28

master
Marc Wäckerlin 11 years ago
parent 9ec9bea1a0
commit da028032e7
  1. 12
      doc/examples/cardos-demo.cxx
  2. 4
      doc/examples/makefile.am
  3. 2
      doc/examples/suisse-id-demo.cxx
  4. 154
      src/cardos.hxx
  5. 19
      src/cryptaux.hxx
  6. 14
      src/suisseid.hxx

@ -40,6 +40,7 @@ class Commands: public cardos::Commands {
<<" (s)elect(f)ile <hex> Select file below master"<<std::endl <<" (s)elect(f)ile <hex> Select file below master"<<std::endl
<<" (s)elect(p)15(f)ile <hex> Select file below PKCS#15"<<std::endl <<" (s)elect(p)15(f)ile <hex> Select file below PKCS#15"<<std::endl
<<" (s)elect(s)igg(f)ile <hex> Select file below SigG"<<std::endl <<" (s)elect(s)igg(f)ile <hex> Select file below SigG"<<std::endl
<<" (r)ead(b)erfile Read selected BER file"<<std::endl
<<" (r)ead(b)in(f)ile Read selected binary file"<<std::endl <<" (r)ead(b)in(f)ile Read selected binary file"<<std::endl
<<" (r)ead(a)bsolute(r)ecord Read absolute record"<<std::endl <<" (r)ead(a)bsolute(r)ecord Read absolute record"<<std::endl
<<" (r)ead(f)irst(r)ecord Read first record"<<std::endl <<" (r)ead(f)irst(r)ecord Read first record"<<std::endl
@ -69,7 +70,8 @@ class Commands: public cardos::Commands {
else if (cmd=="selectfile"||cmd=="sf") selectMfFile(apdu()); else if (cmd=="selectfile"||cmd=="sf") selectMfFile(apdu());
else if (cmd=="selectp15file"||cmd=="spf") selectPkcs15File(apdu()); else if (cmd=="selectp15file"||cmd=="spf") selectPkcs15File(apdu());
else if (cmd=="selectsiggfile"||cmd=="ssf") selectSigGFile(apdu()); else if (cmd=="selectsiggfile"||cmd=="ssf") selectSigGFile(apdu());
else if (cmd=="readbinfile"||cmd=="rbf") _ber=readBinFile(); else if (cmd=="readberfile"||cmd=="rb") _ber=readBerFile();
else if (cmd=="readbinfile"||cmd=="rbf") readBinary();
else if (cmd=="readabsoluterecord"||cmd=="rar") _ber=readRecord(); else if (cmd=="readabsoluterecord"||cmd=="rar") _ber=readRecord();
else if (cmd=="readfirstrecord"||cmd=="rfr") else if (cmd=="readfirstrecord"||cmd=="rfr")
_ber=readRecord(0, 0, FIRST_RECORD); _ber=readRecord(0, 0, FIRST_RECORD);
@ -116,12 +118,12 @@ class Commands: public cardos::Commands {
while (true) { while (true) {
std::string res(send(0x00, 0xB2, 0, NEXT_RECORD)); std::string res(send(0x00, 0xB2, 0, NEXT_RECORD));
if (cardos::Commands::retCode(res)!=0x9000) break; if (cardos::Commands::retCode(res)!=0x9000) break;
cardos::BerValue record(cardos::Commands::retData(res).substr(2)); cardos::BerValues record(cardos::Commands::retData(res).substr(2));
_ber += record; _ber += record;
std::cout<<record[0][0].value() std::cout<<record[0][0][0].string()
<<": len=" <<": len="
<<record[2][0][2].toULong() <<record[0][2][0][2].ulong()
<<"-"<<record[2][0][4].toULong()<<std::endl; <<"-"<<record[0][2][0][4].ulong()<<std::endl;
} }
} }

@ -6,7 +6,8 @@
noinst_HEADERS = suisse-id-demo.hxx noinst_HEADERS = suisse-id-demo.hxx
noinst_PROGRAMS = pcsc-demo cryptoki-sign-demo cryptoki-demo \ noinst_PROGRAMS = pcsc-demo cryptoki-sign-demo cryptoki-demo \
openssl-tcp-demo openssl-ssl-demo \ openssl-tcp-demo openssl-ssl-demo \
openssl-engine-demo suisse-id-demo cardos-demo openssl-engine-demo suisse-id-demo cardos-demo \
create-files-demo
AM_CPPFLAGS += -I${top_srcdir}/src -I/usr/include/PCSC AM_CPPFLAGS += -I${top_srcdir}/src -I/usr/include/PCSC
AM_LDFLAGS = -L${top_builddir}/src -lpcscxx AM_LDFLAGS = -L${top_builddir}/src -lpcscxx
@ -35,6 +36,7 @@ openssl_ssl_demo_SOURCES = openssl-ssl-demo.cxx
openssl_engine_demo_SOURCES = openssl-engine-demo.cxx openssl_engine_demo_SOURCES = openssl-engine-demo.cxx
cardos_demo_SOURCES = cardos-demo.cxx cardos_demo_SOURCES = cardos-demo.cxx
suisse_id_demo_SOURCES = suisse-id-demo.cxx suisse_id_demo_SOURCES = suisse-id-demo.cxx
create_files_demo_SOURCES = create-files-demo.cxx
# moc_suisse-id-demo.cxx # moc_suisse-id-demo.cxx
suisse_id_demo_CXXFLAGS = ${QT_CFLAGS} suisse_id_demo_CXXFLAGS = ${QT_CFLAGS}
suisse_id_demo_LDADD = ${QT_LIBS} suisse_id_demo_LDADD = ${QT_LIBS}

@ -39,7 +39,7 @@ int main(int argc, char** argv) try {
"Sign a text (optionally several times for performance" "Sign a text (optionally several times for performance"
" measurements).", " measurements).",
mrw::args::defaults() mrw::args::defaults()
<<mrw::args::decl("l", "library", "cryptoki lirary to load", <<mrw::args::decl("l", "library", "cryptoki library to load",
mrw::args::decl::param_list() mrw::args::decl::param_list()
<<mrw::args::param(lib, "lib"))); <<mrw::args::param(lib, "lib")));
// now lib contains the dynamic library to load // now lib contains the dynamic library to load

@ -19,7 +19,7 @@
// use e.g. #define CARDOS_LOG(X) std::clog<<X<<std::endl // use e.g. #define CARDOS_LOG(X) std::clog<<X<<std::endl
#endif #endif
/** @defgroup gcardos C++ Access to Siemens CardOS V4.4 /** @defgroup gcardos C++ Access to Siemens CardOS 4.4
Implements APDUs for accessing Siemens CardOS V4.4 smartcards. */ Implements APDUs for accessing Siemens CardOS V4.4 smartcards. */
//@{ //@{
/// @defgroup cardosexception CardOS Exceptions /// @defgroup cardosexception CardOS Exceptions
@ -157,33 +157,44 @@ namespace cardos {
CHARACTER_STRING = 0x1D, CHARACTER_STRING = 0x1D,
BMP_STRING = 0x1E, BMP_STRING = 0x1E,
}; };
public:
BerValue(std::vector<BerValue> sequence): protected: // use BerValues instead
friend class BerValues;
BerValue(const std::vector<BerValue>& sequence):
_tag(PRIVATE|CONSTRUCTED|SEQUENCE), _tag(PRIVATE|CONSTRUCTED|SEQUENCE),
_length(0),
_sequence(sequence) { _sequence(sequence) {
} }
BerValue(const std::string& content) { BerValue(std::string& content) {
if (content.size()<2) if (content.size()<2)
throw wrong_dataformat(content, "not a BER, header size too small: \"" throw wrong_dataformat(content, "not a BER, header size too small: \""
+crypto::binToHex(content)+"\""); +crypto::binToHex(content)+"\"");
_tag = content[0]; _tag = content[0];
_length = content[1]; unsigned char length = content[1];
_value = content.substr(2, _length); _value = content.substr(2, length);
if (std::string::size_type(_length)+2>content.size()) if (content.size()<std::string::size_type(length)+2)
throw wrong_dataformat(content, "not a BER, content size too" throw wrong_dataformat(content, "not a BER, content size too"
" small: \""+crypto::binToHex(_value)+"\""); " small: \""+crypto::binToHex(_value)+"\"");
content.erase(0, 2+length);
if (tagType()==END_OF_CONTENT) return; // done if (tagType()==END_OF_CONTENT) return; // done
if (isContainer()) { if (isContainer())
for (std::string::size_type pos(0); pos+1<_value.size(); while (_value.size()) _sequence.push_back(BerValue(_value));
pos+=2+_value[pos+1]) { // recursively extract value
_sequence.push_back(BerValue(_value.substr(pos, 2+_value[pos+1])));
}
}
} }
public:
BerValue(unsigned char tag, const std::string& value):
_tag(tag), _value(value) {
if (isContainer())
while (_value.size()) _sequence.push_back(BerValue(_value));
}
BerValue(unsigned char tag, const std::vector<BerValue>& values):
_tag(tag), _sequence(values) {
}
unsigned char tagClass() { unsigned char tagClass() {
return _tag&0xC0; return _tag&0xC0;
} }
@ -213,21 +224,31 @@ namespace cardos {
return _sequence[i]; return _sequence[i];
} }
std::string value() { operator std::string() {
std::string res;
res.push_back(_tag);
if (isContainer()) {
for (std::vector<BerValue>::iterator it(_sequence.begin());
it!=_sequence.end(); ++it) {
res += *it;
}
} else {
(res += (char)_value.size()) += _value;
}
return res;
}
std::string string() {
return _value; return _value;
} }
unsigned long toULong() { unsigned long ulong() {
unsigned long res(0); return crypto::ulongFromBinary(_value);
for (std::string::reverse_iterator it(_value.rbegin());
it!=_value.rend(); ++it)
(res<<=8)+=(unsigned)*it;
return res;
} }
std::string print(int indent=0, int indentStep = 4) { std::string print(int indent=0, int indentStep = 4) {
std::stringstream ss; std::stringstream ss;
ss<<std::string(indent*indentStep, ' ')<<'['; ss<<std::string(indent*indentStep, ' ')<<'['<<crypto::binToHex(_tag)<<'=';
switch (tagClass()) { switch (tagClass()) {
case UNIVERSAL: ss<<"UNIVERSAL,"; break; case UNIVERSAL: ss<<"UNIVERSAL,"; break;
case APPLICATION: ss<<"APPLICATION,"; break; case APPLICATION: ss<<"APPLICATION,"; break;
@ -279,7 +300,7 @@ namespace cardos {
for (std::vector<BerValue>::iterator it(_sequence.begin()); for (std::vector<BerValue>::iterator it(_sequence.begin());
it!=_sequence.end(); ++it) { it!=_sequence.end(); ++it) {
ss<<std::string((indent+1)*indentStep, ' ') ss<<std::string((indent+1)*indentStep, ' ')
<<" ["<<i++<<"]{" <<"["<<i++<<"] {"
<<std::endl <<std::endl
<<it->print(indent+2, indentStep) <<it->print(indent+2, indentStep)
<<std::endl <<std::endl
@ -292,15 +313,14 @@ namespace cardos {
for (std::string::const_iterator it(_value.begin()); for (std::string::const_iterator it(_value.begin());
it!=_value.end(); ++it) it!=_value.end(); ++it)
ss<<(isprint(*it)?*it:'.'); ss<<(isprint(*it)?*it:'.');
ss<<"\"";
} }
ss<<"\"";
return ss.str(); return ss.str();
} }
private: private:
unsigned char _tag; unsigned char _tag;
unsigned char _length;
std::string _value; std::string _value;
std::vector<BerValue> _sequence; std::vector<BerValue> _sequence;
@ -309,13 +329,24 @@ namespace cardos {
/// Store a sequence of BerValue /// Store a sequence of BerValue
class BerValues: public std::vector<BerValue> { class BerValues: public std::vector<BerValue> {
public: public:
BerValues& operator=(const std::string& content) { BerValues() {}
BerValues(const std::string& content) {
std::string contentCopy(content);
while (contentCopy.size()) push_back(BerValue(contentCopy));
}
BerValues& operator=(std::string& content) {
clear(); clear();
push_back(BerValue(content)); std::string contentCopy(content);
while (contentCopy.size()) push_back(BerValue(contentCopy));
return *this;
}
BerValues& operator+=(const std::string& content) {
std::string contentCopy(content);
while (contentCopy.size()) push_back(BerValue(contentCopy));
return *this; return *this;
} }
BerValues& operator+=(const BerValue& value) { BerValues& operator+=(const BerValues& values) {
push_back(value); insert(end(), values.begin(), values.end());
return *this; return *this;
} }
std::string print(int indent=0, int indentStep = 4) { std::string print(int indent=0, int indentStep = 4) {
@ -327,7 +358,7 @@ namespace cardos {
ss<<"{"<<std::endl; ss<<"{"<<std::endl;
for (iterator it(begin()); it!=end(); ++it) { for (iterator it(begin()); it!=end(); ++it) {
ss<<std::string((indent+1)*indentStep, ' ') ss<<std::string((indent+1)*indentStep, ' ')
<<" ["<<i++<<"]{" <<"["<<i++<<"] {"
<<std::endl <<std::endl
<<it->print(indent+2, indentStep) <<it->print(indent+2, indentStep)
<<std::endl <<std::endl
@ -590,13 +621,30 @@ namespace cardos {
} }
//! Creates a file (only EF or DF) //! Creates a file (only EF or DF)
void createFile(BerValue) { void createFile(std::string path="", const std::string data="") {
CRYPTOLOG("log"); CRYPTOLOG("log");
// pcsc::Connection::Reader::Transaction lock(_reader);
// if (path.size()) select(path);
// check(send(0x00, 0xE0, 0x00, 0x00,
// check(send(0x00, 0xE0, 0x00, 0x00, BerValue(0x62h, // check(send(0x00, 0xE0, 0x00, 0x00, BerValue(0x62h,
// data).raw())); // data).raw()));
assert(!"not implemented"); assert(!"not implemented");
} }
//! Creates a EF file
void createBinary(std::string path="", std::string id="",
const std::string data="") {
CRYPTOLOG("log");
pcsc::Connection::Reader::Transaction lock(_reader);
if (path.size()) select(path);
BerValues c;
c += BerValue(0x80, crypto::toBinary(data.size()));
std::string idbin(crypto::hexToBin(id));
if (idbin.size()!=2) throw runtime_error("file id must be two bytes");
c += BerValue(0x83, idbin);
check(send(0x00, 0xE0, 0x00, 0x00, BerValue(82, c)));
}
//! Deactivates a file or a file tree //! Deactivates a file or a file tree
void deactivateFile() { void deactivateFile() {
CRYPTOLOG("log"); CRYPTOLOG("log");
@ -618,9 +666,19 @@ namespace cardos {
enum FileTypes {DF=0x00, EF=0x01, DF_EF=0x02}; enum FileTypes {DF=0x00, EF=0x01, DF_EF=0x02};
//! Reads file information of EFs and/or DFs in the current DF //! Reads file information of EFs and/or DFs in the current DF
BerValue directory(FileTypes types, unsigned char offset=0) { BerValues directory(std::string path, FileTypes types=DF_EF,
unsigned char offset=0) {
CRYPTOLOG("log"); CRYPTOLOG("log");
return BerValue(check(send(0x80, 0x16, types, offset))); unsigned char o(offset);
BerValues content;
pcsc::Connection::Reader::Transaction lock(_reader);
if (path.size()) select(path);
/*while (o<(unsigned char)-1)*/ { /// @todo read until done
std::string res(check(send(0x80, 0x16, types, o++)));
//if (cardos::Commands::retCode(res)!=0x9000) break;
content += res;
}
return content;
} }
//! Enables an already loaded and activated but disabled license package. //! Enables an already loaded and activated but disabled license package.
@ -832,8 +890,10 @@ namespace cardos {
} }
//! Read a BINARY file //! Read a BINARY file
std::string readBinary(unsigned short offset = 0) { std::string readBinary(std::string path="", unsigned short offset = 0) {
CRYPTOLOG("log"); CRYPTOLOG("log");
pcsc::Connection::Reader::Transaction lock(_reader);
if (path.size()) select(path);
return check(send(0x00, 0xB0, offset>>8, offset&0xFF)); return check(send(0x00, 0xB0, offset>>8, offset&0xFF));
} }
@ -855,14 +915,15 @@ namespace cardos {
} }
/// Read all records from a record oriented file /// Read all records from a record oriented file
BerValues readBerFile() { BerValues readBerFile(std::string path="") {
CRYPTOLOG("log"); CRYPTOLOG("log");
BerValues content; BerValues content;
pcsc::Connection::Reader::Transaction lock(_reader); pcsc::Connection::Reader::Transaction lock(_reader);
if (path.size()) select(path);
while (true) { while (true) {
std::string res(send(0x00, 0xB2, 0, NEXT_RECORD)); std::string res(send(0x00, 0xB2, 0, NEXT_RECORD));
if (cardos::Commands::retCode(res)!=0x9000) break; if (cardos::Commands::retCode(res)!=0x9000) break;
content += BerValue(retData(res).substr(2)); content += retData(res).substr(2);
} }
return content; return content;
} }
@ -896,13 +957,13 @@ namespace cardos {
}; };
//! Selects a file //! Selects a file
BerValue selectFile(std::string file, BerValues selectFile(std::string file,
FileSelectionMode mode FileSelectionMode mode
= DF_OR_EF_USING_PATH_FROM_MF, = DF_OR_EF_USING_PATH_FROM_MF,
FileSelectionReturn ret FileSelectionReturn ret
= RETURN_NOTHING) { = RETURN_NOTHING) {
CRYPTOLOG("log"); CRYPTOLOG("log");
return BerValue(check(send(0x00, 0xA4, mode, ret, file))); return BerValues(check(send(0x00, 0xA4, mode, ret, file)));
} }
//! Sets the so-called Data_Field_Length parameter relevant for //! Sets the so-called Data_Field_Length parameter relevant for
@ -932,11 +993,12 @@ namespace cardos {
assert(!"not implemented"); assert(!"not implemented");
} }
/// Read the previously file from smart card // same as readBinary
std::string readBinFile() { // /// Read the previously file from smart card
CRYPTOLOG("log"); // std::string readBinFile() {
return check(send(0x00, 0xB0, 0x00, 0x00)); // CRYPTOLOG("log");
} // return check(send(0x00, 0xB0, 0x00, 0x00));
// }
//! Updates a BINARY file //! Updates a BINARY file
void updateBinary(std::string data, unsigned short offset=0) { void updateBinary(std::string data, unsigned short offset=0) {
@ -1123,6 +1185,12 @@ namespace cardos {
check(send(0x00, 0xA4, 0x08, 0x0C, crypto::hexToBin("3f00"+file))); check(send(0x00, 0xA4, 0x08, 0x0C, crypto::hexToBin("3f00"+file)));
} }
/// Generic select file
void select(std::string path) {
CRYPTOLOG("log");
check(send(0x00, 0xA4, 0x08, 0x0C, crypto::hexToBin(path)));
}
/// Select the PKCS#15 part on the smart card /// Select the PKCS#15 part on the smart card
void selectPkcs15() { void selectPkcs15() {
CRYPTOLOG("log"); CRYPTOLOG("log");

@ -163,6 +163,25 @@ namespace crypto {
} }
return res; return res;
} }
/// convert integer to binary of given size
inline std::string toBinary(unsigned long data, int bytes=2) {
std::string res(0, bytes);
for (int i(0); i<bytes; ++i) {
res[bytes-i-1] = data&0xff;
data>>=8;
}
}
/// convert integer from binary of given size
inline unsigned long ulongFromBinary(const std::string& data) {
unsigned long res(0);
for (std::string::const_reverse_iterator it(data.rbegin());
it!=data.rend(); ++it)
(res<<=8)+=(unsigned)*it;
return res;
}
} }
//@} //@}

@ -337,12 +337,12 @@ namespace suisseid {
selectPkcs15File("4408"); selectPkcs15File("4408");
cardos::BerValues res(readBerFile()); cardos::BerValues res(readBerFile());
for (cardos::BerValues::iterator it(res.begin()); it!=res.end(); ++it) for (cardos::BerValues::iterator it(res.begin()); it!=res.end(); ++it)
if ((*it)[0][0].value()=="PIN" || if ((*it)[0][0].string()=="PIN" ||
(*it)[0][0].value()=="Digital Signature PIN") { (*it)[0][0].string()=="Digital Signature PIN") {
if ((*it)[2][0][2].toULong()>_minPinLen) if ((*it)[2][0][2].ulong()>_minPinLen)
_minPinLen = (*it)[2][0][2].toULong(); _minPinLen = (*it)[2][0][2].ulong();
if ((*it)[2][0][4].toULong()<_maxPinLen) if ((*it)[2][0][4].ulong()<_maxPinLen)
_maxPinLen = (*it)[2][0][4].toULong(); _maxPinLen = (*it)[2][0][4].ulong();
} }
} }
@ -350,7 +350,7 @@ namespace suisseid {
pcsc::Connection::Reader::Transaction lock(_reader); pcsc::Connection::Reader::Transaction lock(_reader);
try { try {
selectMfFile(file); selectMfFile(file);
return _version = cardos::BerValue(readBinary())[0].value(); return _version = cardos::BerValues(readBinary())[0].string();
} catch (...) { } catch (...) {
return _version = "<unknown>"; return _version = "<unknown>";
} }

Loading…
Cancel
Save