Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1275521
  • 博文数量: 554
  • 博客积分: 10425
  • 博客等级: 上将
  • 技术积分: 7555
  • 用 户 组: 普通用户
  • 注册时间: 2006-11-09 09:49
文章分类

全部博文(554)

文章存档

2012年(1)

2011年(1)

2009年(8)

2008年(544)

分类:

2008-04-14 11:13:24


Cryptoki 库概述
第9 章• 编写用户级加密应用程序和提供者187
如果tokenPresent 设置为TRUE,则会将搜索限制在那些存在令牌的插槽。
如果pSlotList 设置为NULL_PTR,则C_GetSlotlist() 仅返回插槽的数量。pulCount 是指向
用于接收插槽计数的位置的指针。
如果pSlotList 指向用于接收插槽的缓冲区,则*pulCount 将设置为CK_SLOT_ID 元素的最大
预期数量。在返回时,*pulCount 将设置为CK_SLOT_ID 元素的实际数量。
通常,PKCS #11 应用程序会调用C_GetSlotList() 两次。第一次调用C_GetSlotList() 用于
获取进行内存分配的插槽数量,第二次调用C_GetSlotList() 用于获取插槽。
除了CKR_FUNCTION_FAILED、CKR_GENERAL_ERROR、CKR_HOST_MEMORY 和
CKR_OK 以外,C_GetSlotlist() 还可以获取以下返回值:
 CKR_ARGUMENTS_BAD
 CKR_BUFFER_TOO_SMALL
 CKR_CRYPTOKI_NOT_INITIALIZED
PKCS #11 函数: C_GetTokenInfo()
C_GetTokenInfo() 可用于获取有关特定令牌的信息。C_GetTokenInfo() 使用以下语法:
C_GetTokenInfo(CK_SLOT_ID slotID, CK_TOKEN_INFO_PTR pInfo);
slotID 用于标识令牌的插槽。slotID 必须是由C_GetSlotList() 返回的有效ID。pInfo 是指向
用于接收令牌信息的位置的指针。
如果pkcs11_softtoken.so 是所安装的唯一提供者,则C_GetTokenInfo() 将返回以下字段和
值:
 标记-Sun Software PKCS#11 软令牌。
 标志-CKF_DUAL_CRYPTO_OPERATIONS、CKF_TOKEN_INITIALIZED、CKF_RNG、
CKF_USER_PIN_INITIALIZED 和CKF_LOGIN_REQUIRED,这些标志设置为1。
 ulMaxSessionCount-设置为CK_EFFECTIVELY_INFINITE。
 ulMaxRwSessionCount-设置为CK_EFFECTIVELY_INFINITE。
 ulMaxPinLen-设置为256。
 ulMinPinLen-设置为1。
 ulTotalPublicMemory-设置为CK_UNAVAILABLE_INFORMATION。
 ulFreePublicMemory-设置为CK_UNAVAILABLE_INFORMATION。
 ulTotalPrivateMemory-设置为CK_UNAVAILABLE_INFORMATION。
 ulFreePrivateMemory-设置为CK_UNAVAILABLE_INFORMATION。
除了CKR_FUNCTION_FAILED、CKR_GENERAL_ERROR、CKR_HOST_MEMORY 和
CKR_OK 以外,C_GetSlotlist() 还可以获取以下返回值:
 CKR_ARGUMENTS_BAD
Cryptoki 库概述
188 Solaris 开发者安全性指南• 2006 年11 月
 CKR_BUFFER_TOO_SMALL
 CKR_CRYPTOKI_NOT_INITIALIZED
 CKR_SLOT_ID_INVALID
以下返回值与具有硬件令牌的插件相关:
 CKR_DEVICE_ERROR
 CKR_DEVICE_MEMORY
 CKR_DEVICE_REMOVED
 CKR_TOKEN_NOT_PRESENT
 CKR_TOKEN_NOT_RECOGNIZED
PKCS #11 函数: C_OpenSession()
应用程序可使用C_OpenSession() 来启动特定插槽中具有特定令牌的加密会话。
C_OpenSession() 使用以下语法:
C_OpenSession(CK_SLOT_ID slotID, CK_FLAGS flags, CK_VOID_PTR pApplication,
CK_NOTIFY Notify, CK_SESSION_HANDLE_PTR phSession);
slotID 用于标识插槽。flags 用于指示会话是只读的还是可读写的。pApplication 是应用程序
所定义的用于回调的指针。Notify 用于存放可选回调函数的地址。phSession 是指向会话句柄
的位置的指针。
除了CKR_FUNCTION_FAILED、CKR_GENERAL_ERROR、CKR_HOST_MEMORY 和
CKR_OK 以外,C_OpenSession() 还可以获取以下返回值:
 CKR_ARGUMENTS_BAD
 CKR_CRYPTOKI_NOT_INITIALIZED
 CKR_SLOT_ID_INVALID
 CKR_TOKEN_WRITE_PROTECTED-随受写保护的令牌出现。
以下返回值与具有硬件令牌的插件相关:
 CKR_DEVICE_ERROR
 CKR_DEVICE_MEMORY
 CKR_DEVICE_REMOVED
 CKR_SESSION_COUNT
 CKR_SESSION_PARALLEL_NOT_SUPPORTED
 CKR_SESSION_READ_WRITE_SO_EXISTS
 CKR_TOKEN_NOT_PRESENT
 CKR_TOKEN_NOT_RECOGNIZED
PKCS #11 函数: C_GetMechanismList()
C_GetMechanismList() 可用于获取指定令牌所支持的机制类型的列表。
C_GetMechanismList() 使用以下语法:
Cryptoki 库概述
第9 章• 编写用户级加密应用程序和提供者189
C_GetMechanismList(CK_SLOT_ID slotID, CK_MECHANISM_TYPE_PTR pMechanismList,
CK_ULONG_PTR pulCount);
slotID 用于标识令牌的插槽。pulCount 是指向用于接收机制数量的位置的指针。如果
pMechanismList 设置为NULL_PTR,则*pulCount 将返回机制的数量。否则,必须将
*pulCount 设置为列表的大小,pMechanismList 必须指向用于存放列表的缓冲区。
如果已插入PKCS #11 软令牌,则C_GetMechanismList() 将返回以下列出的支持的机制:
 CKM_AES_CBC
 CKM_AES_CBC_PAD
 CKM_AES_ECB
 CKM_AES_KEY_GEN
 CKM_DES_CBC
 CKM_DES_CBC_PAD
 CKM_DES_ECB
 CKM_DES_KEY_GEN
 CKM_DES_MAC
 CKM_DES_MAC_GENERAL
 CKM_DES3_CBC
 CKM_DES3_CBC_PAD
 CKM_DES3_ECB
 CKM_DES3_KEY_GEN
 CKM_DH_PKCS_DERIVE
 CKM_DH_PKCS_KEY_PAIR_GEN
 CKM_DSA
 CKM_DSA_KEY_PAIR_GEN
 CKM_DSA_SHA_1
 CKM_MD5
 CKM_MD5_KEY_DERIVATION
 CKM_MD5_RSA_PKCS
 CKM_MD5_HMAC
 CKM_MD5_HMAC_GENERAL
 CKM_PBE_SHA1_RC4_128
 CKM_PKCS5_PBKD2
 CKM_RC4
 CKM_RC4_KEY_GEN
 CKM_RSA_PKCS
 CKM_RSA_X_509
 CKM_RSA_PKCS_KEY_PAIR_GEN
 CKM_SHA_1
 CKM_SHA_1_HMAC_GENERAL
 CKM_SHA_1_HMAC
 CKM_SHA_1_KEY_DERIVATION
 CKM_SHA_1_RSA_PKCS
 CKM_SSL3_KEY_AND_MAC_DERIVE
Cryptoki 库概述
190 Solaris 开发者安全性指南• 2006 年11 月
 CKM_SSL3_MASTER_KEY_DERIVE
 CKM_SSL3_MASTER_KEY_DERIVE_DH
 CKM_SSL3_MD5_MAC
 CKM_SSL3_PRE_MASTER_KEY_GEN
 CKM_SSL3_SHA1_MAC
 CKM_TLS_KEY_AND_MAC_DERIVE
 CKM_TLS_MASTER_KEY_DERIVE
 CKM_TLS_MASTER_KEY_DERIVE_DH
 CKM_TLS_PRE_MASTER_KEY_GEN
除了CKR_FUNCTION_FAILED、CKR_GENERAL_ERROR、CKR_HOST_MEMORY 和
CKR_OK 以外,C_GetSlotlist() 还使用以下返回值:
 CKR_ARGUMENTS_BAD
 CKR_BUFFER_TOO_SMALL
 CKR_CRYPTOKI_NOT_INITIALIZED
 CKR_SLOT_ID_INVALID
以下返回值与具有硬件令牌的插件相关:
 CKR_DEVICE_ERROR
 CKR_DEVICE_MEMORY
 CKR_DEVICE_REMOVED
 CKR_TOKEN_NOT_PRESENT
 CKR_TOKEN_NOT_RECOGNIZED
扩展的PKCS #11 函数
除了标准的PKCS #11 函数以外,Solaris 加密框架还附带了两个便利函数:
 第191 页中的“扩展的PKCS #11 函数: SUNW_C_GetMechSession()”
 第192 页中的“扩展的PKCS #11 函数: SUNW_C_KeyToObject”
扩展的PKCS #11 函数: SUNW_C_GetMechSession()
SUNW_C_GetMechSession() 是一个便利函数,用于初始化Solaris 加密框架。该函数随后会使
用指定的机制启动会话。SUNW_C_GetMechSession() 使用以下语法:
SUNW_C_GetMechSession(CK_MECHANISM_TYPE mech, C\
K_SESSION_HANDLE_PTR hSession)
mech 参数用于指定要使用的机制。hSession 是指向会话位置的指针。
SUNW_C_GetMechSession() 在内部调用C_Initialize() 以初始化cryptoki 库。
SUNW_C_GetMechSession() 接着会使用指定的机制调用C_GetSlotList() 和
C_GetMechanismInfo(),在可用插槽中搜索令牌。如果找到了机制,
SUNW_C_GetMechSession() 会调用C_OpenSession() 来打开会话。
Cryptoki 库概述
第9 章• 编写用户级加密应用程序和提供者191
SUNW_C_GetMechSession() 只需要调用一次。不过,多次调用SUNW_C_GetMechSession() 也不
会造成任何问题。
扩展的PKCS #11 函数: SUNW_C_KeyToObject
SUNW_C_KeyToObject() 可用于创建私钥对象。调用程序必须指定要使用的机制以及原始密
钥数据。SUNW_C_KeyToObject() 可在内部确定指定机制的密钥类型。通用密钥对象是通过
C_CreateObject() 创建的。SUNW_C_KeyToObject() 接着会调用C_GetSessionInfo() 和
C_GetMechanismInfo() 来获取插槽和机制。C_SetAttributeValue() 随后会根据机制的类型
为密钥对象设置属性标志。
用户级加密应用程序示例
本节包含以下示例:
 第192 页中的“消息摘要示例”
 第197 页中的“对称加密示例”
 第206 页中的“签名和检验示例”
 第221 页中的“随机字节生成示例”
消息摘要示例
此示例使用PKCS #11 函数通过输入文件创建摘要。该示例执行以下步骤:
1. 指定摘要机制。
此示例中使用的是CKM_MD5 摘要机制。
2. 查找适用于指定摘要算法的插槽。
此示例使用Sun 的便利函数SUNW_C_GetMechSession()。SUNW_C_GetMechSession() 用于
打开cryptoki 库,该库用于存放Solaris 加密框架中所使用的全部PKCS #11 函数。
SUNW_C_GetMechSession() 随后使用所需的机制来查找插槽。然后,将会启动会话。这个
便利函数可有效地替换C_Initialize() 调用、C_OpenSession() 调用以及查找支持指定
机制的插槽所需的任何代码。
3. 获取cryptoki 信息。
本部分实际上不是创建消息摘要所必需的,之所以将其包括在内是为了说明
C_GetInfo() 函数的用法。此示例中将获取制造商ID。其他信息选项用于检索版本和库
数据。
4. 针对插槽执行摘要操作。
此任务中的消息摘要可通过以下三个步骤创建:
a. 打开输入文件。
b. 通过调用C_DigestInit() 来初始化摘要操作。
c. 使用C_DigestUpdate() 逐段处理数据。
d. 使用C_DigestFinal() 获取完整的摘要,从而结束摘要操作过程。
用户级加密应用程序示例
192 Solaris 开发者安全性指南• 2006 年11 月
5. 结束会话。
程序使用C_CloseSession() 关闭会话,使用C_Finalize() 关闭库。
以下示例中显示了消息摘要示例的源代码。
注– 此示例的源代码也可以通过Sun 下载中心获取。请访问

示例9–1 使用PKCS #11 函数创建消息摘要
#include
#include
#include
#include
#include
#include
#define BUFFERSIZ 8192
#define MAXDIGEST 64
/* Calculate the digest of a user supplied file. */
void
main(int argc, char **argv)
{
CK_BYTE digest[MAXDIGEST];
CK_INFO info;
CK_MECHANISM mechanism;
CK_SESSION_HANDLE hSession;
CK_SESSION_INFO Info;
用户级加密应用程序示例
第9 章• 编写用户级加密应用程序和提供者193
示例9–1 使用PKCS #11 函数创建消息摘要(续)
CK_ULONG ulDatalen = BUFFERSIZ;
CK_ULONG ulDigestLen = MAXDIGEST;
CK_RV rv;
CK_SLOT_ID SlotID;
int i, bytes_read = 0;
char inbuf[BUFFERSIZ];
FILE *fs;
int error = 0;
/* Specify the CKM_MD5 digest mechanism as the target */
mechanism.mechanism = CKM_MD5;
mechanism.pParameter = NULL_PTR;
mechanism.ulParameterLen = 0;
/* Use SUNW convenience function to initialize the cryptoki
* library, and open a session with a slot that supports
* the mechanism we plan on using. */
rv = SUNW_C_GetMechSession(mechanism.mechanism, &hSession);
if (rv != CKR_OK) {
fprintf(stderr, "SUNW_C_GetMechSession:rv = 0x%.8X\n", rv);
exit(1);
}
用户级加密应用程序示例
194 Solaris 开发者安全性指南• 2006 年11 月
示例9–1 使用PKCS #11 函数创建消息摘要(续)
/* Get cryptoki information, the manufacturer ID */
rv = C_GetInfo(&info);
if (rv != CKR_OK) {
fprintf(stderr, "WARNING:C_GetInfo:rv = 0x%.8X\n", rv);
}
fprintf(stdout, "Manufacturer ID = %s\n", info.manufacturerID);
/* Open the input file */
if ((fs = fopen(argv[1], "r")) == NULL) {
perror("fopen");
fprintf(stderr, "\n\tusage:%s filename>\n", argv[0]);
error = 1;
goto exit_session;
}
/* Initialize the digest session */
if ((rv = C_DigestInit(hSession, &mechanism)) != CKR_OK) {
fprintf(stderr, "C_DigestInit:rv = 0x%.8X\n", rv);
error = 1;
goto exit_digest;
}
用户级加密应用程序示例
第9 章• 编写用户级加密应用程序和提供者195
示例9–1 使用PKCS #11 函数创建消息摘要(续)
/* Read in the data and create digest of this portion */
while (!feof(fs) && (ulDatalen = fread(inbuf, 1, BUFFERSIZ, fs)) > 0) {
if ((rv = C_DigestUpdate(hSession, (CK_BYTE_PTR)inbuf,
ulDatalen)) != CKR_OK) {
fprintf(stderr, "C_DigestUpdate:rv = 0x%.8X\n", rv);
error = 1;
goto exit_digest;
}
bytes_read += ulDatalen;
}
fprintf(stdout, "%d bytes read and digested!!!\n\n", bytes_read);
/* Get complete digest */
ulDigestLen = sizeof (digest);
if ((rv = C_DigestFinal(hSession, (CK_BYTE_PTR)digest,
&ulDigestLen)) != CKR_OK) {
fprintf(stderr, "C_DigestFinal:rv = 0x%.8X\n", rv);
error = 1;
goto exit_digest;
}
/* Print the results */
fprintf(stdout, "The value of the digest is:");
用户级加密应用程序示例
196 Solaris 开发者安全性指南• 2006 年11 月
示例9–1 使用PKCS #11 函数创建消息摘要(续)
for (i = 0; i < ulDigestLen; i++) {
fprintf(stdout, "%.2x", digest[i]);
}
fprintf(stdout, "\nDone!!!\n");
exit_digest:
fclose(fs);
exit_session:
(void) C_CloseSession(hSession);
exit_program:
(void) C_Finalize(NULL_PTR);
exit(error);
}
对称加密示例
示例9–2 在CBC(密码块链接)模式下使用DES 算法为加密创建了密钥对象。此源代码执
行以下步骤:
1. 声明密钥材料。
定义DES 和初始化向量。以静态方式声明的初始化向量仅用于说明,初始化向量应始终
以动态方式定义并且永远不会重用。
2. 定义密钥对象。
用户级加密应用程序示例
第9 章• 编写用户级加密应用程序和提供者197
对于此任务,必须为密钥设置模板。
3. 查找适用于指定加密机制的插槽。
此示例使用Sun 的便利函数SUNW_C_GetMechSession()。SUNW_C_GetMechSession() 用于
打开cryptoki 库,该库用于存放Solaris 加密框架中所使用的全部PKCS #11 函数。
SUNW_C_GetMechSession() 随后使用所需的机制来查找插槽。然后,将会启动会话。这个
便利函数可有效地替换C_Initialize() 调用、C_OpenSession() 调用以及查找支持指定
机制的插槽所需的任何代码。
4. 在插槽中执行加密操作。
此任务中的加密可通过以下几个步骤执行:
a. 调用C_OpenSession() 来打开会话。
b. 打开输入文件。
c. 创建密钥的对象句柄。
d. 使用机制结构将加密机制设置为CKM_DES_CBC_PAD。
e. 调用C_EncryptInit() 来初始化加密操作。
f. 使用C_EncryptUpdate() 逐段处理数据。
g. 使用C_EncryptFinal() 获取最后一部分加密数据,从而结束加密过程。
5. 在插槽中执行解密操作。
此任务中的解密可通过以下两个步骤执行。提供解密的目的仅是为了进行测试。
a. 调用C_DecryptInit() 来初始化解密操作。
b. 使用C_Decrypt() 处理整个字符串。
6. 结束会话。
程序使用C_CloseSession() 关闭会话,使用C_Finalize() 关闭库。
以下示例中显示了对称加密示例的源代码。
注– 此示例的源代码也可以通过Sun 下载中心获取。请访问

示例9–2 使用PKCS #11 函数创建加密密钥对象
#include
#include
#include
#include
#include
#include
用户级加密应用程序示例
198 Solaris 开发者安全性指南• 2006 年11 月
示例9–2 使用PKCS #11 函数创建加密密钥对象(续)
#define BUFFERSIZ 8192
/* Declare values for the key materials. DO NOT declare initialization
* vectors statically like this in real life!! */
uchar_t des_key[] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef};
uchar_t des_cbc_iv[] = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef};
/* Key template related definitions. */
static CK_BBOOL truevalue = TRUE;
static CK_BBOOL falsevalue = FALSE;
static CK_OBJECT_CLASS class = CKO_SECRET_KEY;
static CK_KEY_TYPE keyType = CKK_DES;
/* Example encrypts and decrypts a file provided by the user. */
void
main(int argc, char **argv)
{
CK_RV rv;
CK_MECHANISM mechanism;
CK_OBJECT_HANDLE hKey;
CK_SESSION_HANDLE hSession;
CK_ULONG ciphertext_len = 64, lastpart_len = 64,
用户级加密应用程序示例
第9 章• 编写用户级加密应用程序和提供者199
示例9–2 使用PKCS #11 函数创建加密密钥对象(续)
ciphertext_space = BUFFERSIZ;
CK_ULONG decrypttext_len;
CK_ULONG total_encrypted = 0;
CK_ULONG ulDatalen = BUFFERSIZ;
CK_SLOT_ID SlotID;
int *pi, i, bytes_read = 0;
int error = 0;
char inbuf[BUFFERSIZ];
FILE *fs;
uchar_t *ciphertext, *pciphertext, *decrypttext;
/* Set the key object */
CK_ATTRIBUTE template[] = {
{CKA_CLASS, &class, sizeof (class) },
{CKA_KEY_TYPE, &keyType, sizeof (keyType) },
{CKA_TOKEN, &falsevalue, sizeof (falsevalue) },
{CKA_ENCRYPT, &truevalue, sizeof (truevalue) },
{CKA_VALUE, &des_key, sizeof (des_key) }
};
/* Set the encryption mechanism to CKM_DES_CBC_PAD */
mechanism.mechanism = CKM_DES_CBC_PAD;
用户级加密应用程序示例
200 Solaris 开发者安全性指南• 2006 年11 月
示例9–2 使用PKCS #11 函数创建加密密钥对象(续)
mechanism.pParameter = des_cbc_iv;
mechanism.ulParameterLen = 8;
/* Use SUNW convenience function to initialize the cryptoki
* library, and open a session with a slot that supports
* the mechanism we plan on using. */
rv = SUNW_C_GetMechSession(mechanism.mechanism, &hSession);
if (rv != CKR_OK) {
fprintf(stderr, "SUNW_C_GetMechSession:rv = 0x%.8X\n", rv);
exit(1);
}
/* Open the input file */
if ((fs = fopen(argv[1], "r")) == NULL) {
perror("fopen");
fprintf(stderr, "\n\tusage:%s filename>\n", argv[0]);
error = 1;
goto exit_session;
}
/* Create an object handle for the key */
rv = C_CreateObject(hSession, template,
用户级加密应用程序示例
第9 章• 编写用户级加密应用程序和提供者201
示例9–2 使用PKCS #11 函数创建加密密钥对象(续)
sizeof (template) / sizeof (CK_ATTRIBUTE),
&hKey);
if (rv != CKR_OK) {
fprintf(stderr, "C_CreateObject:rv = 0x%.8X\n", rv);
error = 1;
goto exit_session;
}
/* Initialize the encryption operation in the session */
rv = C_EncryptInit(hSession, &mechanism, hKey);
if (rv != CKR_OK) {
fprintf(stderr, "C_EncryptInit:rv = 0x%.8X\n", rv);
error = 1;
goto exit_session;
}
/* Read in the data and encrypt this portion */
pciphertext = &ciphertext[0];
while (!feof(fs) && (ciphertext_space > 0) &&
(ulDatalen = fread(inbuf, 1, ciphertext_space, fs)) > 0) {
用户级加密应用程序示例
202 Solaris 开发者安全性指南• 2006 年11 月
示例9–2 使用PKCS #11 函数创建加密密钥对象(续)
ciphertext_len = ciphertext_space;
/* C_EncryptUpdate is only being sent one byte at a
* time, so we are not checking for CKR_BUFFER_TOO_SMALL.
* Also, we are checking to make sure we do not go
* over the alloted buffer size. A more robust program
* could incorporate realloc to enlarge the buffer
* dynamically. */
rv = C_EncryptUpdate(hSession, (CK_BYTE_PTR)inbuf, ulDatalen,
pciphertext, &ciphertext_len);
if (rv != CKR_OK) {
fprintf(stderr, "C_EncryptUpdate:rv = 0x%.8X\n", rv);
error = 1;
goto exit_encrypt;
}
pciphertext += ciphertext_len;
total_encrypted += ciphertext_len;
ciphertext_space -= ciphertext_len;
bytes_read += ulDatalen;
}
if (!feof(fs) || (ciphertext_space < 0)) {
fprintf(stderr, "Insufficient space for encrypting the file\n");
用户级加密应用程序示例
第9 章• 编写用户级加密应用程序和提供者203
示例9–2 使用PKCS #11 函数创建加密密钥对象(续)
error = 1;
goto exit_encrypt;
}
/* Get the last portion of the encrypted data */
lastpart_len = ciphertext_space;
rv = C_EncryptFinal(hSession, pciphertext, &lastpart_len);
if (rv != CKR_OK) {
fprintf(stderr, "C_EncryptFinal:rv = 0x%.8X\n", rv);
error = 1;
goto exit_encrypt;
}
total_encrypted += lastpart_len;
fprintf(stdout, "%d bytes read and encrypted. Size of the "
"ciphertext:%d!\n\n", bytes_read, total_encrypted);
/* Print the encryption results */
fprintf(stdout, "The value of the encryption is:\n");
for (i = 0; i < ciphertext_len; i++) {
if (ciphertext[i] < 16)
fprintf(stdout, "0%x", ciphertext[i]);
else
用户级加密应用程序示例
204 Solaris 开发者安全性指南• 2006 年11 月
示例9–2 使用PKCS #11 函数创建加密密钥对象(续)
fprintf(stdout, "%2x", ciphertext[i]);
}
/* Initialize the decryption operation in the session */
rv = C_DecryptInit(hSession, &mechanism, hKey);
/* Decrypt the entire ciphertext string */
decrypttext_len = sizeof (decrypttext);
rv = C_Decrypt(hSession, (CK_BYTE_PTR)ciphertext, total_encrypted,
decrypttext, &decrypttext_len);
if (rv != CKR_OK) {
fprintf(stderr, "C_Decrypt:rv = 0x%.8X\n", rv);
error = 1;
goto exit_encrypt;
}
fprintf(stdout, "\n\n%d bytes decrypted!!!\n\n", decrypttext_len);
/* Print the decryption results */
fprintf(stdout, "The value of the decryption is:\n%s", decrypttext);
fprintf(stdout, "\nDone!!!\n");
用户级加密应用程序示例
第9 章• 编写用户级加密应用程序和提供者205
示例9–2 使用PKCS #11 函数创建加密密钥对象(续)
exit_encrypt:
fclose(fs);
exit_session:
(void) C_CloseSession(hSession);
exit_program:
(void) C_Finalize(NULL_PTR);
exit(error);
}
签名和检验示例
本节中的示例生成了一个用于对简单字符串进行签名和检验的RSA密钥对。此示例执行以
下步骤:
1. 定义密钥对象。
2. 设置公钥模板。
3. 设置私钥模板。
4. 创建样例消息。
5. 指定用于生成密钥对象的genmech 机制。
6. 指定用于对密钥对进行签名的smech 机制。
7. 初始化cryptoki 库。
8. 通过用于生成和检验密钥对并对其进行签名的机制来查找插槽。此任务将使用一个名为
getMySlot() 的函数来执行以下步骤:
a. 调用C_GetSlotList() 函数以获取可用插槽的列表。
与PKCS #11 约定中所建议的一样,C_GetSlotList() 需要调用两次。第一次调用
C_GetSlotList() 用于获取进行内存分配的插槽数量,第二次调用C_GetSlotList()
用于检索插槽。
用户级加密应用程序示例
206 Solaris 开发者安全性指南• 2006 年11 月
b. 查找可以提供所需机制的插槽。
对于每个插槽,该函数都会调用GetMechanismInfo() 以查找可用于生成密钥对并对
其进行签名的机制。如果插槽不支持这些机制,则GetMechanismInfo() 将返回错
误。如果GetMechanismInfo() 成功返回,则将检查机制标志,以确保这些机制可以
执行所需的操作。
9. 调用C_OpenSession() 来打开会话。
10. 使用C_GenerateKeyPair() 来生成密钥对。
11. 使用C_GetAttributeValue() 显示公钥-仅用于说明。
12. 签名以C_SignInit() 开始,以C_Sign() 结束。
13. 检验以C_VerifyInit() 开始,以C_Verify() 结束。
14. 关闭会话。
程序使用C_CloseSession() 关闭会话,使用C_Finalize() 关闭库。
下面是签名和检验示例的源代码。
注– 此示例的源代码也可以通过Sun 下载中心获取。请访问

示例9–3 使用PKCS #11 函数对文本进行签名和检验
#include
#include
#include
#include
#include
#include
#define BUFFERSIZ 8192
/* Define key template */
static CK_BBOOL truevalue = TRUE;
static CK_BBOOL falsevalue = FALSE;
用户级加密应用程序示例
第9 章• 编写用户级加密应用程序和提供者207
示例9–3 使用PKCS #11 函数对文本进行签名和检验(续)
static CK_ULONG modulusbits = 1024;
static CK_BYTE public_exponent[] = {3};
boolean_t GetMySlot(CK_MECHANISM_TYPE sv_mech, CK_MECHANISM_TYPE kpgen_mech,
CK_SLOT_ID_PTR pslot);
/* Example signs and verifies a simple string, using a public/private
* key pair. */
void
main(int argc, char **argv)
{
CK_RV rv;
CK_MECHANISM genmech, smech;
CK_SESSION_HANDLE hSession;
CK_SESSION_INFO sessInfo;
CK_SLOT_ID slotID;
int error, i = 0;
CK_OBJECT_HANDLE privatekey, publickey;
/* Set public key. */
CK_ATTRIBUTE publickey_template[] = {
{CKA_VERIFY, &truevalue, sizeof (truevalue)},
用户级加密应用程序示例
208 Solaris 开发者安全性指南• 2006 年11 月
示例9–3 使用PKCS #11 函数对文本进行签名和检验(续)
{CKA_MODULUS_BITS, &modulusbits, sizeof (modulusbits)},
{CKA_PUBLIC_EXPONENT, &public_exponent,
sizeof (public_exponent)}
};
/* Set private key. */
CK_ATTRIBUTE privatekey_template[] = {
{CKA_SIGN, &truevalue, sizeof (truevalue)},
{CKA_TOKEN, &falsevalue, sizeof (falsevalue)},
{CKA_SENSITIVE, &truevalue, sizeof (truevalue)},
{CKA_EXTRACTABLE, &truevalue, sizeof (truevalue)}
};
/* Create sample message. */
CK_ATTRIBUTE getattributes[] = {
{CKA_MODULUS_BITS, NULL_PTR, 0},
{CKA_MODULUS, NULL_PTR, 0},
{CKA_PUBLIC_EXPONENT, NULL_PTR, 0}
};
CK_ULONG messagelen, slen, template_size;
boolean_t found_slot = B_FALSE;
用户级加密应用程序示例
第9 章• 编写用户级加密应用程序和提供者209
示例9–3 使用PKCS #11 函数对文本进行签名和检验(续)
uchar_t *message = (uchar_t *)"Simple message for signing & verifying.";
uchar_t *modulus, *pub_exponent;
char sign[BUFFERSIZ];
slen = BUFFERSIZ;
messagelen = strlen((char *)message);
/* Set up mechanism for generating key pair */
genmech.mechanism = CKM_RSA_PKCS_KEY_PAIR_GEN;
genmech.pParameter = NULL_PTR;
genmech.ulParameterLen = 0;
/* Set up the signing mechanism */
smech.mechanism = CKM_RSA_PKCS;
smech.pParameter = NULL_PTR;
smech.ulParameterLen = 0;
/* Initialize the CRYPTOKI library */
rv = C_Initialize(NULL_PTR);
if (rv != CKR_OK) {
fprintf(stderr, "C_Initialize:Error = 0x%.8X\n", rv);
exit(1);
用户级加密应用程序示例
210 Solaris 开发者安全性指南• 2006 年11 月
示例9–3 使用PKCS #11 函数对文本进行签名和检验(续)
}
found_slot = GetMySlot(smech.mechanism, genmech.mechanism, &slotID);
if (!found_slot) {
fprintf(stderr, "No usable slot was found.\n");
goto exit_program;
}
fprintf(stdout, "selected slot:%d\n", slotID);
/* Open a session on the slot found */
rv = C_OpenSession(slotID, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR,
&hSession);
if (rv != CKR_OK) {
fprintf(stderr, "C_OpenSession:rv = 0x%.8X\n", rv);
error = 1;
goto exit_program;
}
fprintf(stdout, "Generating keypair....\n");
用户级加密应用程序示例
第9 章• 编写用户级加密应用程序和提供者211
示例9–3 使用PKCS #11 函数对文本进行签名和检验(续)
/* Generate Key pair for signing/verifying */
rv = C_GenerateKeyPair(hSession, &genmech, publickey_template,
(sizeof (publickey_template) / sizeof (CK_ATTRIBUTE)),
privatekey_template,
(sizeof (privatekey_template) / sizeof (CK_ATTRIBUTE)),
&publickey, &privatekey);
if (rv != CKR_OK) {
fprintf(stderr, "C_GenerateKeyPair:rv = 0x%.8X\n", rv);
error = 1;
goto exit_session;
}
/* Display the publickey. */
template_size = sizeof (getattributes) / sizeof (CK_ATTRIBUTE);
rv = C_GetAttributeValue(hSession, publickey, getattributes,
template_size);
if (rv != CKR_OK) {
/* not fatal, we can still sign/verify if this failed */
fprintf(stderr, "C_GetAttributeValue:rv = 0x%.8X\n", rv);
error = 1;
用户级加密应用程序示例
212 Solaris 开发者安全性指南• 2006 年11 月
示例9–3 使用PKCS #11 函数对文本进行签名和检验(续)
} else {
/* Allocate memory to hold the data we want */
for (i = 0; i < template_size; i++) {
getattributes[i].pValue =
malloc (getattributes[i].ulValueLen *
sizeof(CK_VOID_PTR));
if (getattributes[i].pValue == NULL) {
int j;
for (j = 0; j < i; j++)
free(getattributes[j].pValue);
goto sign_cont;
}
}
/* Call again to get actual attributes */
rv = C_GetAttributeValue(hSession, publickey, getattributes,
template_size);
if (rv != CKR_OK) {
/* not fatal, we can still sign/verify if failed */
fprintf(stderr,
"C_GetAttributeValue:rv = 0x%.8X\n", rv);
error = 1;
用户级加密应用程序示例
第9 章• 编写用户级加密应用程序和提供者213
示例9–3 使用PKCS #11 函数对文本进行签名和检验(续)
} else {
/* Display public key values */
fprintf(stdout, "Public Key data:\n\tModulus bits: "
"%d\n",
*((CK_ULONG_PTR)(getattributes[0].pValue)));
fprintf(stdout, "\tModulus:");
modulus = (uchar_t *)getattributes[1].pValue;
for (i = 0; i < getattributes[1].ulValueLen; i++) {
fprintf(stdout, "%.2x", modulus[i]);
}
fprintf(stdout, "\n\tPublic Exponent:");
pub_exponent = (uchar_t *)getattributes[2].pValue;
for (i = 0; i< getattributes[2].ulValueLen; i++) {
fprintf(stdout, "%.2x", pub_exponent[i]);
}
fprintf(stdout, "\n");
}
}
sign_cont:
rv = C_SignInit(hSession, &smech, privatekey);
用户级加密应用程序示例
214 Solaris 开发者安全性指南• 2006 年11 月
示例9–3 使用PKCS #11 函数对文本进行签名和检验(续)
if (rv != CKR_OK) {
fprintf(stderr, "C_SignInit:rv = 0x%.8X\n", rv);
error = 1;
goto exit_session;
}
rv = C_Sign(hSession, (CK_BYTE_PTR)message, messagelen,
(CK_BYTE_PTR)sign, &slen);
if (rv != CKR_OK) {
fprintf(stderr, "C_Sign:rv = 0x%.8X\n", rv);
error = 1;
goto exit_session;
}
fprintf(stdout, "Message was successfully signed with private key!\n");
rv = C_VerifyInit(hSession, &smech, publickey);
if (rv != CKR_OK) {
fprintf(stderr, "C_VerifyInit:rv = 0x%.8X\n", rv);
error = 1;
用户级加密应用程序示例
第9 章• 编写用户级加密应用程序和提供者215
示例9–3 使用PKCS #11 函数对文本进行签名和检验(续)
goto exit_session;
}
rv = C_Verify(hSession, (CK_BYTE_PTR)message, messagelen,
(CK_BYTE_PTR)sign, slen);
if (rv != CKR_OK) {
fprintf(stderr, "C_Verify:rv = 0x%.8X\n", rv);
error = 1;
goto exit_session;
}
fprintf(stdout, "Message was successfully verified with public key!\n");
exit_session:
(void) C_CloseSession(hSession);
exit_program:
(void) C_Finalize(NULL_PTR);
for (i = 0; i < template_size; i++) {
if (getattributes[i].pValue != NULL)
free(getattributes[i].pValue);
用户级加密应用程序示例
216 Solaris 开发者安全性指南• 2006 年11 月
示例9–3 使用PKCS #11 函数对文本进行签名和检验(续)
}
exit(error);
}
/* Find a slot capable of:
* . signing and verifying with sv_mech
* . generating a key pair with kpgen_mech
* Returns B_TRUE when successful. */
boolean_t GetMySlot(CK_MECHANISM_TYPE sv_mech, CK_MECHANISM_TYPE kpgen_mech,
CK_SLOT_ID_PTR pSlotID)
{
CK_SLOT_ID_PTR pSlotList = NULL_PTR;
CK_SLOT_ID SlotID;
CK_ULONG ulSlotCount = 0;
CK_MECHANISM_INFO mech_info;
int i;
boolean_t returnval = B_FALSE;
CK_RV rv;
/* Get slot list for memory alloction */
用户级加密应用程序示例
第9 章• 编写用户级加密应用程序和提供者217
示例9–3 使用PKCS #11 函数对文本进行签名和检验(续)
rv = C_GetSlotList(0, NULL_PTR, &ulSlotCount);
if ((rv == CKR_OK) && (ulSlotCount > 0)) {
fprintf(stdout, "slotCount = %d\n", ulSlotCount);
pSlotList = malloc(ulSlotCount * sizeof (CK_SLOT_ID));
if (pSlotList == NULL) {
fprintf(stderr, "System error:unable to allocate "
"memory\n");
return (returnval);
}
/* Get the slot list for processing */
rv = C_GetSlotList(0, pSlotList, &ulSlotCount);
if (rv != CKR_OK) {
fprintf(stderr, "GetSlotList failed:unable to get "
"slot count.\n");
goto cleanup;
}
} else {
fprintf(stderr, "GetSlotList failed:unable to get slot "
"list.\n");
return (returnval);
用户级加密应用程序示例
218 Solaris 开发者安全性指南• 2006 年11 月
示例9–3 使用PKCS #11 函数对文本进行签名和检验(续)
}
/* Find a slot capable of specified mechanism */
for (i = 0; i < ulSlotCount; i++) {
SlotID = pSlotList[i];
/* Check if this slot is capable of signing and
* verifying with sv_mech. */
rv = C_GetMechanismInfo(SlotID, sv_mech, &mech_info);
if (rv != CKR_OK) {
continue;
}
if (!(mech_info.flags & CKF_SIGN &&
mech_info.flags & CKF_VERIFY)) {
continue;
}
/* Check if the slot is capable of key pair generation
* with kpgen_mech. */
rv = C_GetMechanismInfo(SlotID, kpgen_mech, &mech_info);
用户级加密应用程序示例
第9 章• 编写用户级加密应用程序和提供者219
示例9–3 使用PKCS #11 函数对文本进行签名和检验(续)
if (rv != CKR_OK) {
continue;
}
if (!(mech_info.flags & CKF_GENERATE_KEY_PAIR)) {
continue;
}
/* If we get this far, this slot supports our mechanisms. */
returnval = B_TRUE;
*pSlotID = SlotID;
break;
}
cleanup:
if (pSlotList)
free(pSlotList);
return (returnval);
}
用户级加密应用程序示例
220 Solaris 开发者安全性指南• 2006 年11 月
随机字节生成示例
示例9–4 说明了如何使用可以生成随机字节的机制来查找插槽。此示例执行以下步骤:
1. 初始化cryptoki 库。
2. 调用GetRandSlot(),以便使用可以生成随机字节的机制来查找插槽。插槽查找任务执
行以下步骤:
a. 调用C_GetSlotList() 函数以获取可用插槽的列表。
与PKCS #11 约定中所建议的一样,C_GetSlotList() 需要调用两次。第一次调用
C_GetSlotList() 用于获取进行内存分配的插槽数量,第二次调用C_GetSlotList()
用于检索插槽。
b. 查找可以生成随机字节的插槽。
对于每个插槽,该函数都可以使用GetTokenInfo() 来获取令牌信息,并在设置了
CKF_RNG 标志的情况下检查匹配项。如果找到设置了CKF_RNG 标志的插槽,则
GetRandSlot() 函数将返回。
3. 使用C_OpenSession() 来打开会话。
4. 使用C_GenerateRandom() 来生成随机字节。
5. 结束会话。
程序使用C_CloseSession() 关闭会话,使用C_Finalize() 关闭库。
随机数生成样例的源代码如以下示例所示。
注– 此示例的源代码也可以通过Sun 下载中心获取。请访问

示例9–4 使用PKCS #11 函数生成随机数
#include
#include
#include
#include
#include
#include
#define RANDSIZE 64
用户级加密应用程序示例
第9 章• 编写用户级加密应用程序和提供者221
示例9–4 使用PKCS #11 函数生成随机数(续)
boolean_t GetRandSlot(CK_SLOT_ID_PTR pslot);
/* Example generates random bytes. */
void
main(int argc, char **argv)
{
CK_RV rv;
CK_MECHANISM mech;
CK_SESSION_HANDLE hSession;
CK_SESSION_INFO sessInfo;
CK_SLOT_ID slotID;
CK_BYTE randBytes[RANDSIZE];
boolean_t found_slot = B_FALSE;
int error;
int i;
/* Initialize the CRYPTOKI library */
rv = C_Initialize(NULL_PTR);
if (rv != CKR_OK) {
fprintf(stderr, "C_Initialize:Error = 0x%.8X\n", rv);
exit(1);
用户级加密应用程序示例
222 Solaris 开发者安全性指南• 2006 年11 月
示例9–4 使用PKCS #11 函数生成随机数(续)
}
found_slot = GetRandSlot(&slotID);
if (!found_slot) {
goto exit_program;
}
/* Open a session on the slot found */
rv = C_OpenSession(slotID, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR,
&hSession);
if (rv != CKR_OK) {
fprintf(stderr, "C_OpenSession:rv = 0x%.8x\n", rv);
error = 1;
goto exit_program;
}
/* Generate random bytes */
rv = C_GenerateRandom(hSession, randBytes, RANDSIZE);
if (rv != CKR_OK) {
fprintf(stderr, "C_GenerateRandom:rv = 0x%.8x\n", rv);
用户级加密应用程序示例
第9 章• 编写用户级加密应用程序和提供者223
示例9–4 使用PKCS #11 函数生成随机数(续)
error = 1;
goto exit_session;
}
fprintf(stdout, "Random value:");
for (i = 0; i < RANDSIZE; i++) {
fprintf(stdout, "%.2x", randBytes[i]);
}
exit_session:
(void) C_CloseSession(hSession);
exit_program:
(void) C_Finalize(NULL_PTR);
exit(error);
}
boolean_t
GetRandSlot(CK_SLOT_ID_PTR pslot)
{
CK_SLOT_ID_PTR pSlotList;
CK_SLOT_ID SlotID;
用户级加密应用程序示例
224 Solaris 开发者安全性指南• 2006 年11 月
示例9–4 使用PKCS #11 函数生成随机数(续)
CK_TOKEN_INFO tokenInfo;
CK_ULONG ulSlotCount;
CK_MECHANISM_TYPE_PTR pMechTypeList = NULL_PTR;
CK_ULONG ulMechTypecount;
boolean_t result = B_FALSE;
int i = 0;
CK_RV rv;
/* Get slot list for memory allocation */
rv = C_GetSlotList(0, NULL_PTR, &ulSlotCount);
if ((rv == CKR_OK) && (ulSlotCount > 0)) {
fprintf(stdout, "slotCount = %d\n", (int)ulSlotCount);
pSlotList = malloc(ulSlotCount * sizeof (CK_SLOT_ID));
if (pSlotList == NULL) {
fprintf(stderr,
"System error:unable to allocate memory\n");
return (result);
}
/* Get the slot list for processing */
用户级加密应用程序示例
第9 章• 编写用户级加密应用程序和提供者225
示例9–4 使用PKCS #11 函数生成随机数(续)
rv = C_GetSlotList(0, pSlotList, &ulSlotCount);
if (rv != CKR_OK) {
fprintf(stderr, "GetSlotList failed:unable to get "
"slot list.\n");
free(pSlotList);
return (result);
}
} else {
fprintf(stderr, "GetSlotList failed:unable to get slot"
" count.\n");
return (result);
}
/* Find a slot capable of doing random number generation */
for (i = 0; i < ulSlotCount; i++) {
SlotID = pSlotList[i];
rv = C_GetTokenInfo(SlotID, &tokenInfo);
if (rv != CKR_OK) {
/* Check the next slot */
continue;
}
用户级加密应用程序示例
226 Solaris 开发者安全性指南• 2006 年11 月
示例9–4 使用PKCS #11 函数生成随机数(续)
if (tokenInfo.flags & CKF_RNG) {
/* Found a random number generator */
*pslot = SlotID;
fprintf(stdout, "Slot # %d supports random number "
"generation!\n", SlotID);
result = B_TRUE;
break;
}
}
if (pSlotList)
free(pSlotList);
return (result);
}
用户级提供者示例
此示例称为演示提供者,是指可用作自定义提供者的基础的工作提供者。此示例可打开
PKCS#11 会话并创建对象。如果该提供者与包含MD5Init()、MD5Update 和MD5Final() 函数
的库链接,则可通过使用CKM_MD5 机制来执行摘要操作。该提供者基于PKCS#11 V2.11。
完整的提供者软件可以从 下载。一
些PKCS#11 函数已在该示例代码中完全实现,而其他一些CS#11 函数仅定义为返回
CKR_FUNCTION_NOT_SUPPORTED。
该示例由以下源代码和头文件组成:
用户级提供者示例
第9 章• 编写用户级加密应用程序和提供者227
 exampleDigest.c -完全实现以下函数:C_DigestInit()、C_Digest()、
C_DigestUpdate()、C_DigestKey() 和C_DigestFinal()。
 exampleDigestUtil.c -包含与摘要有关的实用程序函数。
 exampleAttributeUtil.c -针对属性进行定义、分析、验证和执行各种操作。
 exampleGeneral.c -完全实现以下函数:C_Initialize()、C_Finalize()、
C_GetInfo()、C_GetFunctionList()、C_GetFunctionStatus() 和C_CancelFunction()。
 exampleObject.c -完全实现以下函数:C_CreateObject()、C_CopyObject()、
C_DestroyObject()、C_GetAttributeValue() 和C_SetAttributeValue()。
 exampleObject.h -为密钥、属性和对象提供各种结构和函数原型。
 exampleObjectUtil.c -定义用于管理密钥、对象和属性的特殊函数。
 exampleOps.h -提供示例摘要函数的原型。
 exampleRand.c -完全实现以下函数:C_SeedRandom() 和C_GenerateRandom()。
 exampleRandUtil.c -包含随机数实用程序函数。
 exampleRand.h -提供random_generator() 函数的原型。
 exampleSession.c -完全实现以下函数:C_OpenSession()、C_CloseSession()、
C_CloseAllSessions() 和C_GetSessionInfo()。
 exampleSessionUtil.c -包含与会话有关的实用程序函数。
 exampleSession.h -提供会话所需的各种标志、结构、函数原型和宏。
 exampleSlotToken.c -完全实现C_GetSlotList()、C_GetSlotInfo()、
C_GetTokenInfo()、C_GetMechanismList() 和C_GetMechanismInfo()。
 exampleKeys.c -包含以下可返回CKR_FUNCTION_NOT_SUPPORTED 的函数
:C_GenerateKey()、C_GenerateKeyPair()、C_WrapKey()、C_UnwrapKey() 和
C_DeriveKey()。
 exampleEncrypt.c -包含以下可返回CKR_FUNCTION_NOT_SUPPORTED 的函数
:C_EncryptInit()、C_Encrypt()、C_EncryptUpdate() 和C_EncryptFinal()。
 exampleDecrypt.c -包含以下函数,这些函数可返回
CKR_FUNCTION_NOT_SUPPORTED:C_DecryptInit()、C_Decrypt()、
C_DecryptUpdate() 和C_DecryptFinal()。
 exampleSign.c -包含以下函数,这些函数可返回
CKR_FUNCTION_NOT_SUPPORTED:C_SignInit()、C_Sign()、C_SignUpdate()、
C_SignFinal()、C_SignRecoverInit() 和C_SignRecover()。
 exampleVerify.c -包含以下函数,这些函数可返回
CKR_FUNCTION_NOT_SUPPORTED:C_VerifyInit()、C_Verify()、
C_VerifyUpdate()、C_VerifyFinal()、C_VerifyRecoverInit() 和C_VerifyRecover()。
 exampleDualCrypt.c -包含以下可返回CKR_FUNCTION_NOT_SUPPORTED 的函数
:C_DigestEncryptUpdate()、C_DecryptDigestUpdate()、C_SignEncryptUpdate() 和
C_DecryptVerifyUpdate()。
 exampleGlobal.h -提供全局变量和常数的定义。
用户级提供者示例
228 Solaris 开发者安全性指南• 2006 年11 月
使用智能卡框架
智能卡框架是包含微处理器和内存的便携式计算机。智能卡的形状和大小通常与信用卡相
同。智能卡为可通过验证和加密保护的机密信息提供高度安全存储。
本章包含以下主题:
 第229 页中的“Solaris 智能卡框架概述”
 第230 页中的“开发智能卡消费方应用程序”
 第232 页中的“为智能卡终端开发IFD 处理程序”
 第233 页中的“安装智能卡终端”
Solaris 智能卡框架概述
在Solaris 操作系统中,智能卡框架用于将消费方应用程序与智能卡终端连接起来。消费方
应用程序可以调用智能卡框架(smart card framework, SCF) API。智能卡终端通过接口设备
(interface device, IFD) 处理程序(本质上为设备驱动程序)与消费方应用程序进行通信。IFD
处理程序通过终端接口连接至框架。请参见下图。
10 第1 0 章
229
图10–1智能卡框架
Solaris 操作系统在专用文件中存储智能卡配置信息。与此相反,Linux 实现通常使用
/etc/reader.conf。要更改配置文件中的项,请使用命令smartcard(1M)。
目前,智能卡框架与Solaris 加密框架无关。
开发智能卡消费方应用程序
SCF API 提供了一组用于访问智能卡的接口。这些接口采用低级应用程序协议数据单元
(application protocol data unit,APDU) 形式提供与卡之间的通信。C 和Java 中都提供了这些接
口。这些接口与Solaris 操作系统支持的所有读取器以及与APDU 通信的任何智能卡协同工
作。SCF API 基于以下组件:
 会话对象-每个单个线程的常规上下文,以便避免冲突。
 终端对象-物理智能卡终端的抽象术语。此对象可以检测出是否存在、插入或移除了
卡。
 卡对象-表示插入终端的智能卡。该对象可以采用APDU 格式将信息发送给物理智能
卡。该对象还可以调节互斥锁,以使应用程序可具有对卡进行独占访问的权限。
 侦听器对象-接收事件通知的对象。
SCF API 提供以下领域的功能:
 检查读取器中是否存在智能卡。
 接收智能卡移动(即插入和删除)通知。
 与智能卡交换数据。
 检索有关会话、终端和智能卡的信息。
 锁定和解除锁定要独占访问的智能卡。
以下各节提供有关特定SCF 接口的信息。
开发智能卡消费方应用程序
230 Solaris 开发者安全性指南• 2006 年11 月
SCF 会话接口
以下函数用于SCF 会话。
SCF_Session_getSession(3SMARTCARD)
使用系统的智能卡框架建立会话。打开会话后,可以将该会话与
SCF_Session_getTerminal(3SMARTCARD) 一同使用,以访问智能卡终端。
SCF_Session_close(3SMARTCARD)
释放打开会话时分配的资源。另外,关闭与该会话关联的所有终端或卡。
SCF_Session_getInfo(3SMARTCARD)
获取有关会话的信息。
SCF_Session_freeInfo(3SMARTCARD)
取消从SCF_Session_getInfo(3SMARTCARD) 返回的存储的分配。
SCF_Session_getTerminal(3SMARTCARD)
使用特定的智能卡终端在会话中建立上下文。终端对象用于检测卡移动(即插入或删
除)。终端对象还用于创建用于访问特定卡的卡对象。
SCF 终端接口
以下函数用于访问SCF 终端。
SCF_Terminal_close(3SMARTCARD)
释放打开终端时分配的资源。该函数还可以关闭所有与终端关联的卡。
SCF_Terminal_getInfo(3SMARTCARD)
获取有关终端的信息。
SCF_Terminal_freeInfo(3SMARTCARD)
取消从SCF_Terminal_getInfo(3SMARTCARD) 返回的存储的分配。
SCF_Terminal_waitForCardPresent(3SMARTCARD)
阻塞并等待,直到指定终端中出现卡为止。
SCF_Terminal_waitForCardAbsent(3SMARTCARD)
阻塞并等待,直到指定终端中移除卡为止。
SCF_Terminal_addEventListener(3SMARTCARD)
在终端发生事件时,允许程序接收回叫通知。此概念与信号处理程序类似。发生事件
时,服务线程将执行提供的回叫函数。
SCF_Terminal_updateEventListener(3SMARTCARD)
更新与此终端关联的指定事件侦听器。
SCF_Terminal_removeEventListener(3SMARTCARD)
从与此终端关联的侦听器列表中删除指定的事件侦听器。
 
 
以上文章转自于 : http://developers.sun.com.cn/
阅读(1193) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~