Oracle® Solaris 11 セキュリティー開発者ガイド

印刷ビューの終了

更新: 2014 年 7 月
 
 

KMF アプリケーションの完全なソースコード

KMF API の定義については、libkmf(3LIB) のマニュアルページを参照してください。

    このアプリケーションは次の手順を実行します。

  1. KMF 関数を呼び出す前に、アプリケーションはまず kmf_initialize() を使用して、KMF セッション用のハンドルを初期化する必要があります。このハンドルは、ほとんどの KMF 関数呼び出しの最初の引数として使用されます。これは不透明なデータ型で、そのセッションの内部状態およびコンテキスト情報を保持するために使用されます。

  2. このアプリケーション例では PKCS#11 キーストアを使用します。kmf_configure_keystore() を使用して、今後の操作のために使用するトークンを定義します。

  3. 証明書または PKCS#10 CSR を作成する最初のステップは鍵ペアを作成することです。kmf_create_keypair() を使用して、必要となる公開鍵および非公開鍵の両方を作成し、指定されたキーストアに非公開鍵を保管します。関数はアプリケーションにハンドルを返すため、呼び出し元は今後の操作で必要な場合に公開鍵および非公開鍵オブジェクトを参照できます。

  4. 鍵ペアが設定されたら、kmf_set_cert_pubkey() および kmf_set_cert_version() を使用して、最終証明書を生成するために使用するテンプレートレコードにデータを取り込みます。KMF は拡張機能を含め、X.509v3 証明書の各種フィールドを設定するためのさまざまな API を提供します。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 構造体を作成します。

  5. これは自己証明証明書の作成演習であるため、このアプリケーションは上記で作成された証明書テンプレートを、証明書それ自身の公開鍵と合った秘密鍵で署名します。この kmf_sign_cert() 操作の結果は、ASN.1 でエンコードされた X.509v3 証明書データを格納する KMF_DATA レコードになります。

  6. 証明書は署名されて最終的なフォーマットになったため、証明書はどのキーストアにも保管できます。kmf_store_cert() を使用して、このアプリケーションの先頭で定義されている PKCS#11 トークンに証明書を保管します。証明書はこの時点で NSS または OpenSSL ファイルに保管することも可能です。

  7. KMF によって生成されたデータ構造体に対して割り当てられたメモリーは、データ構造体が不要になったときにクリーンアップする必要があります。KMF には、これらのオブジェクトに関連付けられたメモリーを適切に割り当て解除するための便利な API が提供されています。リソースを節約するためにメモリーを適切にクリーンアップすることを強くお勧めします。クリーンアップインタフェースは、kmf_free_data()kmf_free_dn()、および kmf_finalize() を含んでいます。

次に、すべてのデータ型およびヘルパー関数を含むアプリケーション例の完全なソースコードを示します。コンパイルの後、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);
}