JavaScript is required to for searching.
Skip Navigation Links
Exit Print View
Developer's Guide to Oracle Solaris 11 Security     Oracle Solaris 11.1 Information Library
search filter icon
search icon

Document Information

Preface

1.  Oracle Solaris Security for Developers (Overview)

2.  Developing Privileged Applications

3.  Writing PAM Applications and Services

4.  Writing Applications That Use GSS-API

5.  GSS-API Client Example

6.  GSS-API Server Example

7.  Writing Applications That Use SASL

8.  Introduction to the Oracle Solaris Cryptographic Framework

9.  Writing User-Level Cryptographic Applications

Overview of the Cryptoki Library

PKCS #11 Function List

Functions for Using PKCS #11

PKCS #11 Functions: C_Initialize()

PKCS #11 Functions: C_GetInfo()

PKCS #11 Functions: C_GetSlotList()

PKCS #11 Functions: C_GetTokenInfo()

PKCS #11 Functions: C_OpenSession()

PKCS #11 Functions: C_GetMechanismList()

Extended PKCS #11 Functions

Extended PKCS #11 Functions: SUNW_C_GetMechSession()

Extended PKCS #11 Functions: SUNW_C_KeyToObject

User-Level Cryptographic Application Examples

Message Digest Example

Symmetric Encryption Example

Sign and Verify Example

Random Byte Generation Example

10.  Introduction to the Oracle Solaris Key Management Framework

A.  Secure Coding Guidelines for Developers

B.  Sample C-Based GSS-API Programs

C.  GSS-API Reference

D.  Specifying an OID

E.  Source Code for SASL Example

F.  SASL Reference Tables

Glossary

Index

User-Level Cryptographic Application Examples

This section includes the following examples:

Message Digest Example

This example uses PKCS #11 functions to create a digest from an input file. The example performs the following steps:

  1. Specifies the digest mechanism.

    In this example, the CKM_MD5 digest mechanism is used.

  2. Finds a slot that is capable of the specified digest algorithm.

    This example uses the Oracle Solaris convenience function SUNW_C_GetMechSession(). SUNW_C_GetMechSession() opens the cryptoki library, which holds all the PKCS #11 functions that are used in the Oracle Solaris cryptographic framework. SUNW_C_GetMechSession() then finds the slot with the desired mechanism. The session is then started. Effectively, this convenience function replaces the C_Initialize() call, the C_OpenSession() call, and any code needed to find a slot that supports the specified mechanism.

  3. Obtains cryptoki information.

    This part is not actually needed to create the message digest, but is included to demonstrate use of the C_GetInfo() function. This example gets the manufacturer ID. The other information options retrieve version and library data.

  4. Conducts a digest operation with the slot.

    The message digest is created in this task through these steps:

    1. Opening the input file.

    2. Initializing the digest operation by calling C_DigestInit().

    3. Processing the data a piece at a time with C_DigestUpdate().

    4. Ending the digest process by using C_DigestFinal() to get the complete digest.

  5. Ends the session.

    The program uses C_CloseSession() to close the session and C_Finalize() to close the library.

The source code for the message digest example is shown in the following example.


Note - The source code for this example is also available through the Oracle download center. See http://www.oracle.com/technetwork/indexes/downloads/sdlc-decommission-333274.html.


Example 9-1 Creating a Message Digest Using PKCS #11 Functions

#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 MAXDIGEST    64

/* Calculate the digest of a user supplied file. */
void
main(int argc, char **argv)
{
    CK_BYTE digest[MAXDIGEST];
    CK_INFO info;
    CK_MECHANISM mechanism;
    CK_SESSION_HANDLE hSession;
    CK_SESSION_INFO Info;
    CK_ULONG ulDatalen = BUFFERSIZ;
    CK_ULONG ulDigestLen = MAXDIGEST;
    CK_RV rv;
    CK_SLOT_ID SlotID;

    int i, bytes_read = 0;
    char inbuf[BUFFERSIZ];
    FILE *fs;
    int error = 0;

    /* Specify the CKM_MD5 digest mechanism as the target */
    mechanism.mechanism = CKM_MD5;
    mechanism.pParameter = NULL_PTR;
    mechanism.ulParameterLen = 0;

    /* Use SUNW convenience function to initialize the cryptoki
     * library, and open a session with a slot that supports
     * the mechanism we plan on using. */
    rv = SUNW_C_GetMechSession(mechanism.mechanism, &hSession);
    if (rv != CKR_OK) {
        fprintf(stderr, "SUNW_C_GetMechSession: rv = 0x%.8X\n", rv);
        exit(1);
    }

    /* Get cryptoki information, the manufacturer ID */
    rv = C_GetInfo(&info);
    if (rv != CKR_OK) {
        fprintf(stderr, "WARNING: C_GetInfo: rv = 0x%.8X\n", rv);
    }
    fprintf(stdout, "Manufacturer ID = %s\n", info.manufacturerID);

    /* Open the input file */
    if ((fs = fopen(argv[1], "r")) == NULL) {
        perror("fopen");
        fprintf(stderr, "\n\tusage: %s filename>\n", argv[0]);
        error = 1;
        goto exit_session;
    }

    /* Initialize the digest session */
    if ((rv = C_DigestInit(hSession, &mechanism)) != CKR_OK) {
        fprintf(stderr, "C_DigestInit: rv = 0x%.8X\n", rv);
        error = 1;
        goto exit_digest;
    }

    /* Read in the data and create digest of this portion */
    while (!feof(fs) && (ulDatalen = fread(inbuf, 1, BUFFERSIZ, fs)) > 0) {
        if ((rv = C_DigestUpdate(hSession, (CK_BYTE_PTR)inbuf,
                    ulDatalen)) != CKR_OK) {
            fprintf(stderr, "C_DigestUpdate: rv = 0x%.8X\n", rv);
            error = 1;
            goto exit_digest;
        }
        bytes_read += ulDatalen;
    }
    fprintf(stdout, "%d bytes read and digested!!!\n\n", bytes_read);

    /* Get complete digest */
    ulDigestLen = sizeof (digest);
    if ((rv = C_DigestFinal(hSession, (CK_BYTE_PTR)digest,
                &ulDigestLen)) != CKR_OK) {
        fprintf(stderr, "C_DigestFinal: rv = 0x%.8X\n", rv);
        error = 1;
        goto exit_digest;
    }

    /* Print the results */
    fprintf(stdout, "The value of the digest is: ");
    for (i = 0; i < ulDigestLen; i++) {
        fprintf(stdout, "%.2x", digest[i]);
    }
    fprintf(stdout, "\nDone!!!\n");

exit_digest:
    fclose(fs);

exit_session:
    (void) C_CloseSession(hSession);

exit_program:
    (void) C_Finalize(NULL_PTR);

    exit(error);

}

Symmetric Encryption Example

Example 9-2 creates a key object for encryption with the DES algorithm in the CBC mode. This source code performs the following steps:

  1. Declares key materials.

    Defines DES and initialization vector. The initialization vector is declared statically for demonstration purposes only. Initialization vectors should always be defined dynamically and never reused.

  2. Defines a key object.

    For this task, you have to set up a template for the key.

  3. Finds a slot that is capable of the specified encryption mechanism.

    This example uses the Oracle Solaris convenience function SUNW_C_GetMechSession(). SUNW_C_GetMechSession() opens the cryptoki library, which holds all the PKCS #11 functions that are used in the Oracle Solaris cryptographic framework. SUNW_C_GetMechSession() then finds the slot with the desired mechanism. The session is then started. Effectively, this convenience function replaces the C_Initialize() call, the C_OpenSession() call, and any code needed to find a slot that supports the specified mechanism.

  4. Conducts an encryption operation in the slot.

    The encryption is performed in this task through these steps:

    1. Opening the input file.

    2. Creating an object handle for the key.

    3. Setting the encryption mechanism to CKM_DES_CBC_PAD by using the mechanism structure.

    4. Initializing the encryption operation by calling C_EncryptInit().

    5. Processing the data a piece at a time with C_EncryptUpdate().

    6. Ending the encryption process by using C_EncryptFinal() to get the last portion of the encrypted data.

  5. Conducts a decryption operation in the slot.

    The decryption is performed in this task through these steps. The decryption is provided for testing purposes only.

    1. Initializes the decryption operation by calling C_DecryptInit().

    2. Processes the entire string with C_Decrypt().

  6. Ends the session.

    The program uses C_CloseSession() to close the session and C_Finalize() to close the library.

The source code for the symmetric encryption example is shown in the following example.


Note - The source code for this example is also available through the Oracle download center. See http://www.oracle.com/technetwork/indexes/downloads/sdlc-decommission-333274.html.


Example 9-2 Creating an Encryption Key Object Using PKCS #11 Functions

#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <security/cryptoki.h>
#include <security/pkcs11.h>

#define BUFFERSIZ    8192

/* Declare values for the key materials. DO NOT declare initialization 
 * vectors statically like this in real life!! */
uchar_t des_key[] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef};
uchar_t des_cbc_iv[] = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef};

/* Key template related definitions. */
static CK_BBOOL truevalue = TRUE;
static CK_BBOOL falsevalue = FALSE;
static CK_OBJECT_CLASS class = CKO_SECRET_KEY;
static CK_KEY_TYPE keyType = CKK_DES;


/* Example encrypts and decrypts a file provided by the user. */
void
main(int argc, char **argv)
{
    CK_RV rv;
    CK_MECHANISM mechanism;
    CK_OBJECT_HANDLE hKey;
    CK_SESSION_HANDLE hSession;
    CK_ULONG ciphertext_len = 64, lastpart_len = 64;
    long ciphertext_space = BUFFERSIZ;
    CK_ULONG decrypttext_len;
    CK_ULONG total_encrypted = 0;
    CK_ULONG ulDatalen = BUFFERSIZ;

    int i, bytes_read = 0;
    int error = 0;
    char inbuf[BUFFERSIZ];
    FILE *fs;
    uchar_t ciphertext[BUFFERSIZ], *pciphertext, decrypttext[BUFFERSIZ];

    /* Set the key object */
    CK_ATTRIBUTE template[] = {
        {CKA_CLASS, &class, sizeof (class) },
        {CKA_KEY_TYPE, &keyType, sizeof (keyType) },
        {CKA_TOKEN, &falsevalue, sizeof (falsevalue) },
        {CKA_ENCRYPT, &truevalue, sizeof (truevalue) },
        {CKA_VALUE, &des_key, sizeof (des_key) }
    };

    /* Set the encryption mechanism to CKM_DES_CBC_PAD */
    mechanism.mechanism = CKM_DES_CBC_PAD;
    mechanism.pParameter = des_cbc_iv;
    mechanism.ulParameterLen = 8;

    /* Use SUNW convenience function to initialize the cryptoki
     * library, and open a session with a slot that supports
     * the mechanism we plan on using. */
    rv = SUNW_C_GetMechSession(mechanism.mechanism, &hSession);

    if (rv != CKR_OK) {
        fprintf(stderr, "SUNW_C_GetMechSession: rv = 0x%.8X\n", rv);
        exit(1);
    }

    /* Open the input file */
    if ((fs = fopen(argv[1], "r")) == NULL) {
        perror("fopen");
        fprintf(stderr, "\n\tusage: %s filename>\n", argv[0]);
        error = 1;
        goto exit_session;
    }

    /* Create an object handle for the key */
    rv = C_CreateObject(hSession, template,
        sizeof (template) / sizeof (CK_ATTRIBUTE),
        &hKey);

    if (rv != CKR_OK) {
        fprintf(stderr, "C_CreateObject: rv = 0x%.8X\n", rv);
        error = 1;
        goto exit_session;
    }


    /* Initialize the encryption operation in the session */
    rv = C_EncryptInit(hSession, &mechanism, hKey);

    if (rv != CKR_OK) {
        fprintf(stderr, "C_EncryptInit: rv = 0x%.8X\n", rv);
        error = 1;
        goto exit_session;
    }

    /* Read in the data and encrypt this portion */
    pciphertext = &ciphertext[0];
    while (!feof(fs) && (ciphertext_space > 0) &&
        (ulDatalen = fread(inbuf, 1, ciphertext_space, fs)) > 0) {
        ciphertext_len = ciphertext_space;

        /* C_EncryptUpdate is only being sent one byte at a
         * time, so we are not checking for CKR_BUFFER_TOO_SMALL.
         * Also, we are checking to make sure we do not go
         * over the alloted buffer size.  A more robust program
         * could incorporate realloc to enlarge the buffer
         * dynamically.     */
        rv = C_EncryptUpdate(hSession, (CK_BYTE_PTR)inbuf, ulDatalen,
            pciphertext, &ciphertext_len);
        if (rv != CKR_OK) {
            fprintf(stderr, "C_EncryptUpdate: rv = 0x%.8X\n", rv);
            error = 1;
            goto exit_encrypt;
        }
        pciphertext += ciphertext_len;
        total_encrypted += ciphertext_len;
        ciphertext_space -= ciphertext_len;
        bytes_read += ulDatalen;
    }

    if (!feof(fs) || (ciphertext_space < 0)) {
        fprintf(stderr, "Insufficient space for encrypting the file\n");
        error = 1;
        goto exit_encrypt;
    }

    /* Get the last portion of the encrypted data */
    lastpart_len = ciphertext_space;
    rv = C_EncryptFinal(hSession, pciphertext, &lastpart_len);
    if (rv != CKR_OK) {
        fprintf(stderr, "C_EncryptFinal: rv = 0x%.8X\n", rv);
        error = 1;
        goto exit_encrypt;
    }
    total_encrypted += lastpart_len;

    fprintf(stdout, "%d bytes read and encrypted. Size of the "
        "ciphertext: %d!\n\n", bytes_read, total_encrypted);

    /* Print the encryption results */
    fprintf(stdout, "The value of the encryption is:\n");
    for (i = 0; i < ciphertext_len; i++) {
        if (ciphertext[i] < 16)
            fprintf(stdout, "0%x", ciphertext[i]);
        else
            fprintf(stdout, "%2x", ciphertext[i]);
    }

    /* Initialize the decryption operation in the session */
    rv = C_DecryptInit(hSession, &mechanism, hKey);

    /* Decrypt the entire ciphertext string */
    decrypttext_len = sizeof (decrypttext);
    rv = C_Decrypt(hSession, (CK_BYTE_PTR)ciphertext, total_encrypted,
        decrypttext, &decrypttext_len);

    if (rv != CKR_OK) {
        fprintf(stderr, "C_Decrypt: rv = 0x%.8X\n", rv);
        error = 1;
        goto exit_encrypt;
    }

    fprintf(stdout, "\n\n%d bytes decrypted!!!\n\n", decrypttext_len);

    /* Print the decryption results */
    fprintf(stdout, "The value of the decryption is:\n%s", decrypttext);

    fprintf(stdout, "\nDone!!!\n");

exit_encrypt:
    fclose(fs);

exit_session:
    (void) C_CloseSession(hSession);

exit_program:
    (void) C_Finalize(NULL_PTR);
    exit(error);
}

Sign and Verify Example

The example in this section generates an RSA key pair. The key pair is used to sign and verify a simple string. The example goes through the following steps:

  1. Defines a key object.

  2. Sets the public key template.

  3. Sets the private key template.

  4. Creates a sample message.

  5. Specifies the genmech mechanism, which generates the key pair.

  6. Specifies the smech mechanism, which signs the key pair.

  7. Initializes the cryptoki library.

  8. Finds a slot with mechanisms for signing, verifying, and key pair generation.

    The task uses a function that is called getMySlot(), which performs the following steps:

    1. Calling the function C_GetSlotList() to get a list of the available slots.

      C_GetSlotList() is called twice, as the PKCS #11 convention suggests. C_GetSlotList() is called the first time to get the number of slots for memory allocation. C_GetSlotList() is called the second time to retrieve the slots.

    2. Finding a slot that can supply the desired mechanisms.

      For each slot, the function calls GetMechanismInfo() to find mechanisms for signing and for key pair generation. If the mechanisms are not supported by the slot, GetMechanismInfo() returns an error. If GetMechanismInfo() returns successfully, then the mechanism flags are checked to make sure the mechanisms can perform the needed operations.

  9. Opens the session by calling C_OpenSession().

  10. Generates the key pair by using C_GenerateKeyPair().

  11. Displays the public key with C_GetAttributeValue() – For demonstration purposes only.

  12. Signing is started with C_SignInit() and completed with C_Sign().

  13. Verification is started with C_VerifyInit() and completed with C_Verify().

  14. Closes the session.

    The program uses C_CloseSession() to close the session and C_Finalize() to close the library.

The source code for the sign-and-verify example follows.


Note - The source code for this example is also available through the Oracle download center. See http://www.oracle.com/technetwork/indexes/downloads/sdlc-decommission-333274.html.


Example 9-3 Signing and Verifying Text Using PKCS #11 Functions

#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);

}

Random Byte Generation Example

Example 9-4 demonstrates how to find a slot with a mechanism that can generate random bytes. The example performs the following steps:

  1. Initializes the cryptoki library.

  2. Calls GetRandSlot() to find a slot with a mechanism that can generate random bytes.

    The task of finding a slot performs the following steps:

    1. Calling the function C_GetSlotList() to get a list of the available slots.

      C_GetSlotList() is called twice, as the PKCS #11 convention suggests. C_GetSlotList() is called the first time to get the number of slots for memory allocation. C_GetSlotList() is called the second time to retrieve the slots.

    2. Finding a slot that can generate random bytes.

      For each slot, the function obtains the token information by using GetTokenInfo() and checks for a match with the CKF_RNG flag set. When a slot that has the CKF_RNG flag set is found, the GetRandSlot() function returns.

  3. Opens the session by using C_OpenSession().

  4. Generates random bytes by using C_GenerateRandom().

  5. Ends the session.

    The program uses C_CloseSession() to close the session and C_Finalize() to close the library.

The source code for the random number generation sample is shown in the following example.


Note - The source code for this example is also available through the Oracle download center. See http://www.oracle.com/technetwork/indexes/downloads/sdlc-decommission-333274.html.


Example 9-4 Generating Random Numbers Using PKCS #11 Functions

#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <security/cryptoki.h>
#include <security/pkcs11.h>

#define RANDSIZE 64

boolean_t GetRandSlot(CK_SLOT_ID_PTR pslot);

/* Example generates random bytes. */
void
main(int argc, char **argv)
{
    CK_RV   rv;
    CK_MECHANISM mech;
    CK_SESSION_HANDLE hSession;
    CK_SESSION_INFO sessInfo;
    CK_SLOT_ID slotID;
    CK_BYTE randBytes[RANDSIZE];

    boolean_t found_slot = B_FALSE;
    int error;
    int i;

    /* 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 = GetRandSlot(&slotID);

    if (!found_slot) {
        goto exit_program;
    }

    /* 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;
    }

    /* Generate random bytes */
    rv = C_GenerateRandom(hSession, randBytes, RANDSIZE);

    if (rv != CKR_OK) {
        fprintf(stderr, "C_GenerateRandom: rv = 0x%.8x\n", rv);
        error = 1;
        goto exit_session;
    }

    fprintf(stdout, "Random value: ");
    for (i = 0; i < RANDSIZE; i++) {
        fprintf(stdout, "%.2x", randBytes[i]);
    }

exit_session:
    (void) C_CloseSession(hSession);

exit_program:
    (void) C_Finalize(NULL_PTR);
    exit(error);

}

boolean_t
GetRandSlot(CK_SLOT_ID_PTR pslot)
{
    CK_SLOT_ID_PTR pSlotList;
    CK_SLOT_ID SlotID;
    CK_TOKEN_INFO tokenInfo;
    CK_ULONG ulSlotCount;
    CK_MECHANISM_TYPE_PTR pMechTypeList = NULL_PTR;
    CK_ULONG ulMechTypecount;
    boolean_t result = B_FALSE;
    int i = 0;

    CK_RV rv;

    /* Get slot list for memory allocation */
    rv = C_GetSlotList(0, NULL_PTR, &ulSlotCount);

    if ((rv == CKR_OK) && (ulSlotCount > 0)) {
        fprintf(stdout, "slotCount = %d\n", (int)ulSlotCount);
        pSlotList = malloc(ulSlotCount * sizeof (CK_SLOT_ID));

        if (pSlotList == NULL) {
            fprintf(stderr,
                "System error: unable to allocate memory\n");
            return (result);
        }

        /* Get the slot list for processing */
        rv = C_GetSlotList(0, pSlotList, &ulSlotCount);
        if (rv != CKR_OK) {
            fprintf(stderr, "GetSlotList failed: unable to get "
                "slot list.\n");
            free(pSlotList);
            return (result);
        }
    } else {
        fprintf(stderr, "GetSlotList failed: unable to get slot"
            " count.\n");
        return (result);
    }

    /* Find a slot capable of doing random number generation */
    for (i = 0; i < ulSlotCount; i++) {
        SlotID = pSlotList[i];

        rv = C_GetTokenInfo(SlotID, &tokenInfo);

        if (rv != CKR_OK) {
            /* Check the next slot */
            continue;
        }

        if (tokenInfo.flags & CKF_RNG) {
            /* Found a random number generator */
            *pslot = SlotID;
            fprintf(stdout, "Slot # %d supports random number "
                "generation!\n", SlotID);
            result = B_TRUE;
            break;
        }
    }

    if (pSlotList)
        free(pSlotList);

    return (result);

}