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