JavaScript is required to for searching.
跳过导航链接
退出打印视图
Oracle Solaris 11 开发者安全性指南     Oracle Solaris 11.1 Information Library (简体中文)
为本文档评分
search filter icon
search icon

文档信息

前言

1.  面向开发者的 Oracle Solaris 安全(概述)

2.  开发特权应用程序

3.  编写 PAM 应用程序和服务

4.  编写使用 GSS-API 的应用程序

5.  GSS-API 客户机示例

6.  GSS-API 服务器示例

7.  编写使用 SASL 的应用程序

8.  Oracle Solaris 加密框架介绍

9.  编写用户级加密应用程序

Cryptoki 库概述

PKCS #11 函数列表

使用 PKCS #11 的函数

PKCS #11 函数:C_Initialize()

PKCS #11 函数:C_GetInfo()

PKCS #11 函数:C_GetSlotList()

PKCS #11 函数:C_GetTokenInfo()

PKCS #11 函数:C_OpenSession()

PKCS #11 函数:C_GetMechanismList()

扩展的 PKCS #11 函数

扩展的 PKCS #11 函数:SUNW_C_GetMechSession()()

扩展的 PKCS #11 函数:SUNW_C_KeyToObject

用户级加密应用程序示例

消息摘要示例

对称加密示例

签名和验证示例

随机字节生成示例

10.  Oracle Solaris 密钥管理框架介绍

A.  适用于开发者的安全编码准则

B.  基于 C 的 GSS-API 样例程序

C.  GSS-API 参考信息

D.  指定 OID

E.  SASL 示例的源代码

F.  SASL 参考信息表

词汇表

索引

请告诉我们如何提高我们的文档:
过于简略
不易阅读或难以理解
重要信息缺失
错误的内容
需要翻译的版本
其他
Your rating has been updated
感谢您的反馈!

您的反馈将非常有助于我们提供更好的文档。 您是否愿意参与我们的内容改进并提供进一步的意见?

用户级加密应用程序示例

本节包含以下示例:

消息摘要示例

此示例使用 PKCS #11 函数基于输入文件创建摘要。此示例执行以下步骤:

  1. 指定摘要机制。

    此示例中使用的是 CKM_MD5 摘要机制。

  2. 查找适用于指定摘要算法的插槽。

    此示例使用 Orace Solaris 的便利函数 SUNW_C_GetMechSession()SUNW_C_GetMechSession() 用 于打开 cryptoki 库,该库用于存放 Oracle Solaris 加密框架中所使用的全部 PKCS #11 函数。SUNW_C_GetMechSession() 随后使用所需的机制来查找插槽。然后,将会启动会话。这个便利函数可有效地替换 C_Initialize() 调用、C_OpenSession() 调用以及查找支持指定机制的插槽所需的任何代码。

  3. 获取 cryptoki 信息。

    本部分实际上不是创建消息摘要所必需的,之所以将其包括在内是为了说明 C_GetInfo() 函数的用法。此示例中将获取制造商 ID。其他信息选项用于检索版本和库数据。

  4. 针对插槽执行摘要操作。

    此任务中的消息摘要可通过以下几个步骤创建:

    1. 打开输入文件。

    2. 通过调用 C_DigestInit() 来初始化摘要操作。

    3. 使用 C_DigestUpdate() 逐段处理数据。

    4. 使用 C_DigestFinal() 获取完整的摘要,从而结束摘要操作过程。

  5. 结束会话。

    程序使用 C_CloseSession() 关闭会话,使用 C_Finalize() 关闭库。

以下示例中显示了消息摘要示例的源代码。


注 - 此示例的源代码也可以通过 Oracle 下载中心获取。请参见 http://www.oracle.com/technetwork/indexes/downloads/sdlc-decommission-333274.html


示例 9-1 使用 PKCS #11 函数创建消息摘要

#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <security/cryptoki.h>
#include <security/pkcs11.h>

#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;
    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);
    }

    /* 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;
    }

    /* 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: ");
    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. 定义密钥对象。

    对于此任务,必须为密钥设置模板。

  3. 查找适用于指定加密机制的插槽。

    此示例使用 Oracle Solaris 的便利函数 SUNW_C_GetMechSession()SUNW_C_GetMechSession() 用 于打开 cryptoki 库,该库用于存放 Oracle Solaris 加密框架中所使用的全部 PKCS #11 函数。SUNW_C_GetMechSession() 随后使用所需的机制来查找插槽。然后,将会启动会话。这个便利函数可有效地替换 C_Initialize() 调用、C_OpenSession() 调用以及查找支持指定机制的插槽所需的任何代码。

  4. 在插槽中执行加密操作。

    此任务中的加密可通过以下几个步骤执行:

    1. 打开输入文件。

    2. 创建密钥的对象句柄。

    3. 使用机制结构将加密机制设置为 CKM_DES_CBC_PAD。

    4. 调用 C_EncryptInit() 来初始化加密操作。

    5. 使用 C_EncryptUpdate() 逐段处理数据。

    6. 使用 C_EncryptFinal() 获取最后一部分加密数据,从而结束加密过程。

  5. 在插槽中执行解密操作。

    此任务中的解密可通过以下几个步骤执行。提供解密的目的仅是为了进行测试。

    1. 调用 C_DecryptInit() 来初始化解密操作。

    2. 使用 C_Decrypt() 处理整个字符串。

  6. 结束会话。

    程序使用 C_CloseSession() 关闭会话,使用 C_Finalize() 关闭库。

以下示例中显示了对称加密示例的源代码。


注 - 此示例的源代码也可以通过 Oracle 下载中心获取。请参见 http://www.oracle.com/technetwork/indexes/downloads/sdlc-decommission-333274.html


示例 9-2 使用 PKCS #11 函数创建加密密钥对象

#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <security/cryptoki.h>
#include <security/pkcs11.h>

#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;
    long ciphertext_space = BUFFERSIZ;
    CK_ULONG decrypttext_len;
    CK_ULONG total_encrypted = 0;
    CK_ULONG ulDatalen = BUFFERSIZ;

    int i, bytes_read = 0;
    int error = 0;
    char inbuf[BUFFERSIZ];
    FILE *fs;
    uchar_t ciphertext[BUFFERSIZ], *pciphertext, decrypttext[BUFFERSIZ];

    /* 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;
    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,
        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) {
        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");
        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
            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");

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() 的函数来执行以下步骤:

    1. 调用 C_GetSlotList() 函数以获取可用插槽的列表。

      与 PKCS #11 约定中所建议的一样,C_GetSlotList() 需要调用两次。第一次调用 C_GetSlotList() 用于获取进行内存分配的插槽数量,第二次调用 C_GetSlotList() 用于检索插槽。

    2. 查找可以提供所需机制的插槽。

      对于每个插槽,该函数都会调用 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() 关闭库。

下面是签名和验证示例的源代码。


注 - 此示例的源代码也可以通过 Oracle 下载中心获取。请参见 http://www.oracle.com/technetwork/indexes/downloads/sdlc-decommission-333274.html


示例 9-3 使用 PKCS #11 函数对文本进行签名和验证

#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <security/cryptoki.h>
#include <security/pkcs11.h>

#define BUFFERSIZ    8192

/* Define key template */
static CK_BBOOL truevalue = TRUE;
static CK_BBOOL falsevalue = FALSE;
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)},
        {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;
    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);
    }

    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");

    /* 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;
    } 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;
        } 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);

    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;
        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);
    }

    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 */
    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);
    }

    /* 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);

        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);

}

随机字节生成示例

示例 9-4 说明如何使用可生成随机字节的机制查找插槽。此示例执行以下步骤:

  1. 初始化 cryptoki 库。

  2. 调用 GetRandSlot(),以便使用可以生成随机字节的机制来查找插槽。

    插槽查找任务执行以下步骤:

    1. 调用 C_GetSlotList() 函数以获取可用插槽的列表。

      与 PKCS #11 约定中所建议的一样,C_GetSlotList() 需要调用两次。第一次调用 C_GetSlotList() 用于获取进行内存分配的插槽数量,第二次调用 C_GetSlotList() 用于检索插槽。

    2. 查找可以生成随机字节的插槽。

      对于每个插槽,该函数都可以使用 GetTokenInfo() 来获取令牌信息,并在设置了 CKF_RNG 标志的情况下检查匹配项。如果找到设置了 CKF_RNG 标志的插槽,则 GetRandSlot() 函数将返回。

  3. 使用 C_OpenSession() 来打开会话。

  4. 使用 C_GenerateRandom() 来生成随机字节。

  5. 结束会话。

    程序使用 C_CloseSession() 关闭会话,使用 C_Finalize() 关闭库。

随机数生成样例的源代码如以下示例所示。


注 - 此示例的源代码也可以通过 Oracle 下载中心获取。请参见 http://www.oracle.com/technetwork/indexes/downloads/sdlc-decommission-333274.html


示例 9-4 使用 PKCS #11 函数生成随机数

#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <security/cryptoki.h>
#include <security/pkcs11.h>

#define RANDSIZE 64

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);
    }

    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);
        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;
    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 */
        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;
        }

        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);

}