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() は 2 回呼び出されます。1 回目の C_GetSlotList() 呼び出しでは、メモリーを割り当てる目的でスロット数を取得します。そして 2 回目の 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);

}