面向开发者的 Oracle® Solaris 11 安全性指南

退出打印视图

更新时间: 2014 年 7 月
 
 

签名和验证示例

    本节中的示例生成了一个 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() 关闭库。

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

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

}