跳过导航链接 | |
退出打印视图 | |
Oracle Solaris 11 开发者安全性指南 Oracle Solaris 11.1 Information Library (简体中文) |
pktool 应用程序是有关如何使用 KMF API 的极佳示例。
本节说明一个使用 KMF 的简单应用程序。本节介绍为执行某些 KMF 操作,应用程序所需执行的基本步骤。此示例假设您有 C 编程方面的经验,并且对公钥技术和标准有基本了解。此示例介绍初始化 KMF 以供使用的步骤,然后创建自签名 X.509v3 证书和关联的 RSA 密钥对。此外,此示例还说明如何使用 KMF 增强的 pktool 命令来验证应用程序是否已成功。
要让程序可以访问 KMF 函数原型和类型定义,请包含 kmfapi.h 文件。
#include <stdio.h> #include <kmfapi.h>
请确保在链接步骤中包含 KMF 库。
$ cc -o kmftest kmftest.c -lkmf
有关结果和类型的定义,请参见 kmftypes.h 文件。此示例使用以下 KMF 类型的变量。
KMF 调用的会话句柄
所有 KMF 调用的返回代码
KMF 密钥的句柄
KMF 凭证
请确保足够大
密钥库类型,如 KMF_KEYSTORE_PK11TOKEN
密钥类型,如 KMF_RSA
获得签名的数据记录
标识名记录
最终证书数据记录
变量长度整数
通过使用 pktool(1M) 实用程序,用户可以验证程序是否已成功创建证书和密钥对。
$ pktool list objtype=both Enter pin for Sun Software PKCS#11 softtoken : Found 1 certificates. 1. (X.509 certificate) Label: admin@foobar.com ID: 09:ac:7f:1a:01:f7:fc:a9:1a:cd:fd:8f:d4:92:4c:25:bf:b1:97:fe Subject: C=US, ST=CA, L=Menlo Park, O=Foobar Inc., OU=Foobar IT Office, CN=admin@foobar.com Issuer: C=US, ST=CA, L=Menlo Park, O=Foobar Inc., OU=Foobar IT Office, CN=admin@foobar.com Serial: 0x452BF693 X509v3 Subject Alternative Name: email:admin@foobar.com Found 1 keys. Key #1 - RSA private key: admin@foobar.com
有关 KMF API 的定义,请参见 libkmf(3LIB) 手册页。
此应用程序执行以下步骤:
在可以调用任何 KMF 函数之前,应用程序必须首先使用 kmf_initialize() 来初始化 KMF 会话的句柄。此句柄用作大多数 KMF 函数调用的第一个参数。它是一个不透明的数据类型,用于保留该会话的内部状态和上下文信息。
此示例应用程序使用 PKCS#11 密钥库。使用 kmf_configure_keystore() 来定义将来操作要使用的令牌。
创建证书或 PKCS#10 CSR 的第一步是生成密钥对。使用 kmf_create_keypair() 来创建所需的公钥和私钥,并将私钥存储在指定密钥库中。该函数会将句柄返回到应用程序,以便调用者可以在将来的操作中引用公钥和私钥对象(如有必要)。
建立密钥对后,使用 kmf_set_cert_pubkey() 和 kmf_set_cert_version() 来填充用于生成最终证书的模板记录。KMF 可提供不同的 API 来设置 X.509v3 证书的各种字段(包括扩展)。使用 kmf_hexstr_to_bytes()、kmf_set_cert_serial()、kmf_set_cert_validity() 和 kmf_set_cert_sig_alg() 来设置序列号。该序列号是 KMF_BIGINT 记录。使用 kmf_dn_parser()、kmf_set_cert_subject() 和 kmf_set_cert_issuer() 来创建 KMF_X509_NAME 结构。
由于这是自签名证书创建练习,所以该应用程序使用随证书自身的公钥提供的私钥对上面创建的证书模板进行签名。该 kmf_sign_cert() 操作将导致生成 KMF_DATA 记录,该记录包含 ASN.1 编码的 X.509v3 证书数据。
现在,已对证书进行签名并且为其最终格式,可以将其存储在任何密钥库中。使用 kmf_store_cert() 将证书存储在该应用程序开始时定义的 PKCS#11 令牌中。此时,也可以将证书存储在 NSS 或 OpenSSL 文件中。
不再需要 KMF 生成的数据结构时,应清除分配给该数据结构的内存。KMF 提供了便于使用的 API,以便正确地解除与这些对象关联的内存的分配。为了节省资源,强烈建议正确地清除内存。清除接口包括 kmf_free_data()、kmf_free_dn() 和 kmf_finalize()。
下面是此示例应用程序的完整源代码,包括所有数据类型和辅助 (helper) 函数。编译时,请确保包含 KMF 库。
/* * KMF Example code for generating a self-signed X.509 certificate. * This is completely unsupported and is just to be used as an example. * * Compile: * $ cc -o keytest keytest.c -lkmf * * Run: * $ ./keytest * * Once complete, the results can be verified using the pktool(1) command: * * $ pktool list * This should show an RSA public key labeled "keytest" and a cert labeled "keytest". * * The objects created by this program can be deleted from the keystore * using pktool(1) also: * * $ pktool delete label=keytest * */ #include <stdio.h> #include <strings.h> #include <fcntl.h> #include <sys/types.h> #include <sys/stat.h> #include <tzfile.h> #include <kmfapi.h> int main(int argc, char *argv[]) { KMF_HANDLE_T kmfhandle; KMF_RETURN ret; char opt, *str = NULL; extern char *optarg; KMF_KEY_HANDLE prikey, pubkey; KMF_CREDENTIAL cred; KMF_ATTRIBUTE attrlist[16]; /* this needs to be big enough */ KMF_KEYSTORE_TYPE kstype; KMF_KEY_ALG keytype; KMF_KEY_HANDLE prik, pubk; KMF_X509_CERTIFICATE certstruct; KMF_X509_NAME certsubject, certissuer; KMF_DATA rawcert; KMF_BIGINT serno; char *token = "Sun Software PKCS#11 softtoken"; char *keylabel = "keytest"; boolean_t readonly = B_FALSE; uint32_t keylen = 1024; uint32_t ltime = SECSPERDAY * DAYSPERNYEAR; /* seconds in a year (see tzfile.h) */ char prompt[1024]; int numattrs; (void) memset(&certstruct, 0, sizeof (certstruct)); (void) memset(&rawcert, 0, sizeof (rawcert)); (void) memset(&certissuer, 0, sizeof (certissuer)); (void) memset(&certsubject, 0, sizeof (certsubject)); /* * Initialize a KMF handle for use in future calls. */ ret = kmf_initialize(&kmfhandle, NULL, NULL); if (ret != KMF_OK) { printf("kmf_initialize failed: 0x%0x\n", ret); exit(1); } /* We want to use the PKCS11 keystore */ kstype = KMF_KEYSTORE_PK11TOKEN; numattrs = 0; kmf_set_attr_at_index(attrlist, numattrs, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattrs++; /* Indicate which PKCS11 token will be used */ kmf_set_attr_at_index(attrlist, numattrs, KMF_TOKEN_LABEL_ATTR, token, strlen(token)); numattrs++; kmf_set_attr_at_index(attrlist, numattrs, KMF_READONLY_ATTR, &readonly, sizeof (readonly)); numattrs++; ret = kmf_configure_keystore(kmfhandle, numattrs, attrlist); if (ret != KMF_OK) exit (ret); /* Reset the attribute count for a new command */ numattrs = 0; /* * Get the PIN to access the token. */ (void) snprintf(prompt, sizeof (prompt), "Enter PIN for %s:", token); cred.cred = getpassphrase(prompt); if (cred.cred != NULL) { cred.credlen = strlen(cred.cred); kmf_set_attr_at_index(attrlist, numattrs, KMF_CREDENTIAL_ATTR, &cred, sizeof (cred)); numattrs++; } kmf_set_attr_at_index(attrlist, numattrs, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattrs++; keytype = KMF_RSA; keylen = 1024; keylabel = "keytest"; kmf_set_attr_at_index(attrlist, numattrs, KMF_KEYALG_ATTR, &keytype, sizeof (keytype)); numattrs++; kmf_set_attr_at_index(attrlist, numattrs, KMF_KEYLENGTH_ATTR, &keylen, sizeof (keylen)); numattrs++; kmf_set_attr_at_index(attrlist, numattrs, KMF_KEYLABEL_ATTR, keylabel, strlen(keylabel)); numattrs++; kmf_set_attr_at_index(attrlist, numattrs, KMF_CREDENTIAL_ATTR, &cred, sizeof (cred)); numattrs++; /* * Set the handles so they can be used later. */ kmf_set_attr_at_index(attrlist, numattrs, KMF_PRIVKEY_HANDLE_ATTR, &prik, sizeof (prik)); numattrs++; kmf_set_attr_at_index(attrlist, numattrs, KMF_PUBKEY_HANDLE_ATTR, &pubk, sizeof (pubk)); numattrs++; ret = kmf_create_keypair(kmfhandle, numattrs, attrlist); if (ret != KMF_OK) { printf("kmf_create_keypair error: 0x%02x\n", ret); goto cleanup; } /* * Now the keys have been created, generate an X.509 certificate * by populating the template and signing it. */ if ((ret = kmf_set_cert_pubkey(kmfhandle, &pubk, &certstruct))) { printf("kmf_set_cert_pubkey error: 0x%02x\n", ret); goto cleanup; } /* Version "2" is for an x509.v3 certificate */ if ((ret = kmf_set_cert_version(&certstruct, 2))) { printf("kmf_set_cert_version error: 0x%02x\n", ret); goto cleanup; } /* * Set up the serial number, it must be a KMF_BIGINT record. */ if ((ret = kmf_hexstr_to_bytes((uchar_t *)"0x010203", &serno.val, \ &serno.len))) { printf("kmf_hexstr_to_bytes error: 0x%02x\n", ret); goto cleanup; } if ((ret = kmf_set_cert_serial(&certstruct, &serno))) { printf("kmf_set_cert_serial error: 0x%02x\n", ret); goto cleanup; } if ((ret = kmf_set_cert_validity(&certstruct, NULL, ltime))) { printf("kmf_set_cert_validity error: 0x%02x\n", ret); goto cleanup; } if ((ret = kmf_set_cert_sig_alg(&certstruct, KMF_ALGID_SHA1WithRSA))) { printf("kmf_set_cert_sig_alg error: 0x%02x\n", ret); goto cleanup; } /* * Create a KMF_X509_NAME struct by parsing a distinguished name. */ if ((ret = kmf_dn_parser("cn=testcert", &certsubject))) { printf("kmf_dn_parser error: 0x%02x\n", ret); goto cleanup; } if ((ret = kmf_dn_parser("cn=testcert", &certissuer))) { printf("kmf_dn_parser error: 0x%02x\n", ret); goto cleanup; } if ((ret = kmf_set_cert_subject(&certstruct, &certsubject))) { printf("kmf_set_cert_sig_alg error: 0x%02x\n", ret); goto cleanup; } if ((ret = kmf_set_cert_issuer(&certstruct, &certissuer))) { printf("kmf_set_cert_sig_alg error: 0x%02x\n", ret); goto cleanup; } /* * Now we have the certstruct setup with the minimal amount needed * to generate a self-signed cert. Put together the attributes to * call kmf_sign_cert. */ numattrs = 0; kmf_set_attr_at_index(attrlist, numattrs, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattrs++; kmf_set_attr_at_index(attrlist, numattrs, KMF_KEY_HANDLE_ATTR, &prik, sizeof (KMF_KEY_HANDLE_ATTR)); numattrs++; /* The X509 template structure to be signed goes here. */ kmf_set_attr_at_index(attrlist, numattrs, KMF_X509_CERTIFICATE_ATTR, &certstruct, sizeof (KMF_X509_CERTIFICATE)); numattrs++; /* * Set the output buffer for the signed cert. * This will be a block of raw ASN.1 data. */ kmf_set_attr_at_index(attrlist, numattrs, KMF_CERT_DATA_ATTR, &rawcert, sizeof (KMF_DATA)); numattrs++; if ((ret = kmf_sign_cert(kmfhandle, numattrs, attrlist))) { printf("kmf_sign_cert error: 0x%02x\n", ret); goto cleanup; } /* * Now we have the certificate and we want to store it in the * keystore (which is the PKCS11 token in this example). */ numattrs = 0; kmf_set_attr_at_index(attrlist, numattrs, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); numattrs++; kmf_set_attr_at_index(attrlist, numattrs, KMF_CERT_DATA_ATTR, &rawcert, sizeof (KMF_DATA)); numattrs++; /* Use the same label as the public key */ kmf_set_attr_at_index(attrlist, numattrs, KMF_CERT_LABEL_ATTR, keylabel, strlen(keylabel)); numattrs++; if ((ret = kmf_store_cert(kmfhandle, numattrs, attrlist))) { printf("kmf_store_cert error: 0x%02x\n", ret); goto cleanup; } cleanup: kmf_free_data(&rawcert); kmf_free_dn(&certissuer); kmf_free_dn(&certsubject); kmf_finalize(kmfhandle); return (ret); }