使用 pkcs#11 从智能卡读取文本文件
Posted
技术标签:
【中文标题】使用 pkcs#11 从智能卡读取文本文件【英文标题】:Read text file from smart card with pkcs#11 【发布时间】:2016-02-25 13:25:47 【问题描述】:我有一张空白智能卡 (SLE66CX322P, Cardos 4.3b)
和一个读卡器/写卡器 (Gemalto CT 40)
。使用软件我可以初始化卡、生成密钥、证书等。我还可以创建一个简单的 ASCII
文件,其中包含一些将存储在智能卡上的文本。我的问题是,如何使用pkcs#11 API
读取C/C++
中此ASCII 文件的内容?
这是我迄今为止尝试过的(也使用 Qt):
---------- cardreader.h ------------
#ifndef CARDREADER_H
#define CARDREADER_H
#include "cm-pkcs11.h"
#include <QCoreApplication>
#include <QObject>
#include <QtDebug>
class CardReader: public QObject
Q_OBJECT
private:
CK_RV rv;
CK_ULONG slotCount;
CK_SLOT_ID slotIds[10];
CK_SLOT_ID slotId;
CK_SESSION_HANDLE session;
CK_TOKEN_INFO_PTR info;
void readCard();
public:
explicit CardReader(QObject *parent = 0);
;
#endif // CARDREADER_H
------- cardreader.cpp ----------
#include "cardreader.h"
CardReader::CardReader(QObject *parent) : QObject(parent)
readCard();
/***********************************************************************/
void CardReader::readCard()
rv = C_Initialize(NULL_PTR);
slotCount = 10;
rv = C_GetSlotList(CK_TRUE, slotIds, &slotCount);
qWarning() << "Found" << slotCount << "slots";
if (rv != CKR_OK || slotCount < 1)
qWarning() << "No slots found -> exit";
return;
slotId = slotIds[0];
rv = C_OpenSession(slotId, CKF_SERIAL_SESSION|CKF_RW_SESSION, NULL_PTR, NULL_PTR, &session);
if (rv != CKR_OK)
qWarning() << "Sessions could not be opened -> exit";
qWarning() << "RV (as hex value) = " << QString("%1").arg(rv, 0, 16);
return;
/*********************************************************************/
CK_OBJECT_CLASS dataClass = CKO_DATA;
CK_OBJECT_HANDLE handleObject;
CK_UTF8CHAR label[] = "MyLabel";
CK_ULONG ulCount = 4ul;
CK_CHAR application[] = "TestApplication";
CK_BYTE dataValue[] = "MyData";
CK_BBOOL valid = CK_TRUE;
CK_ATTRIBUTE dataTemp[] =
CKA_CLASS, &dataClass, sizeof(dataClass),
CKA_VALUE, dataValue, sizeof(dataValue),
CKA_LABEL, label, sizeof(label)-1,
//CKA_APPLICATION, application, sizeof(application)
CKA_TOKEN, &valid, sizeof(true)
;
rv = C_FindObjectsInit(session, dataTemp, 0);
if (rv != CKR_OK)
qWarning() << "C_FindObjectsInit Error -> exit";
qWarning() << "C_FindObjectsInit Error" << QString("%1").arg(rv, 0, 16);
return;
while (1)
rv = C_FindObjects(session, &handleObject, 1, &ulCount);
qWarning() << "C_FindObjects Result =" << QString("%1").arg(rv, 0, 16) << ", count =" << ulCount;
if (rv != CKR_OK || ulCount == 0)
break;
rv = C_GetAttributeValue(session, handleObject, dataTemp, ulCount);
if (rv != CKR_OK)
qWarning() << "C_GetAttributeValue error -> exit";
qWarning() << "RV (as hex value) = " << QString("%1").arg(rv, 0, 16) << ", count = " << ulCount;
return;
qWarning() << (const char *) dataTemp[0].pValue;
qWarning() << (const char *) dataTemp[1].pValue;
qWarning() << (const char *) dataTemp[2].pValue;
qWarning() << (const char *) dataTemp[3].pValue;
---------- main.cpp ----------
#include "cardreader.h"
int main(int argc, char *argv[])
QCoreApplication a(argc, argv);
CardReader c;
return a.exec();
结果是块
qWarning() << (const char *) dataTemp[0].pValue;
qWarning() << (const char *) dataTemp[1].pValue;
qWarning() << (const char *) dataTemp[2].pValue;
qWarning() << (const char *) dataTemp[3].pValue;
在控制台中打印了四次,但总是以MyLabel
和MyData
作为我在CardReader::readCard()
开头指定的结果。智能卡上的文本文件的内容当然是不同的,但遗憾的是没有显示在输出中。
我还想提一下,我还能够使用C_CreateObject()
函数。这在智能卡上生成了第二个 ASCII 文件。但是我的代码也无法读取第二个文件。
【问题讨论】:
【参考方案1】:最可能的原因:
您的ulCount
变量被C_FindObjects()
覆盖为1
。
在调用C_GetAttributeValue
之前,您需要再次将其重新分配给4
。
这样您的代码只读取模板中的第一个属性。
一些额外的(随机的)注释:
由于您不调用C_Login()
,因此您只能查看/访问公共对象(设置为 CKA_PRIVATE 的对象为您隐藏)。
C_FindObjectsInit()
的零 ulCount
参数会导致您的代码枚举所有令牌对象 - 您可能希望 CKA_CLASS
和 CKA_LABEL
过滤器有效。
我建议不要对C_FindObjectsInit()
和C_GetAttributeValue()
使用相同的模板
您的 dataValue
缓冲区非常小 -- 您确定该值适合吗?
祝你好运!
【讨论】:
谢谢,你的提示解决了。我已将4
重新分配给ulCount
,将C_FindObjectsInit()
的最后一个参数更改为1,并增加了dataValue
和label
的缓冲区。但是,我不确定C_FindObjectsInit()
中的CK_ULONG
值是做什么的。当我输入 2
时,我没有得到任何结果。通过1
,我得到了我的芯片卡的内容。 0
给了我更多不可读字符的结果。我认为CK_ULONG
值告诉我文本文件有多少属性必须适合模板,以及两个属性。适合:dataValue
和 label
。
@Varius C_FindObjectsInit()
的 CK_ULONG ulCount
参数定义了搜索模板中匹配的属性(及其值)的数量。在您的情况下,0="所有对象"、1="CKA_CLASS==CKO_DATA 的对象"和 2="CKA_CLASS==CKO_DATA 和 CKA_VALUE==MyData 的对象"。由于您的数据对象可能不包含“MyData”,因此您的搜索不会为您提供ulCount=2
的结果。这有意义吗?
此外,您不应将属性值 (pValue
) 视为以零结尾的字符串。您应该使用valueLen
字段来确定输出长度并仅转储有效字节。
并且您应该在调用C_GetAttributeValue()
之前重置模板中的所有字段valueLen
。
好的,谢谢。现在这是有道理的。事实上,我的卡上没有任何带有MyData
的文件。所以ulCount=1
给了我所有CKO_DATA
类型的文件,独立于它们的CKA_VALUE
。而ulCount=2
会给我所有CKO_DATA
类型的文件和“MyData”的值(如果我在卡上有这样的文件......)。现在明白了。谢谢以上是关于使用 pkcs#11 从智能卡读取文本文件的主要内容,如果未能解决你的问题,请参考以下文章
Excel VBA 如何从 Web 读取文本文件(未缓存)?