root/usr/src/lib/pkcs11/pkcs11_softtoken/common/softKeystore.c
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
 * Copyright 2020 Joyent, Inc.
 */

#include <crypt.h>
#include <cryptoutil.h>
#include <pwd.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/sysmacros.h>
#include <security/cryptoki.h>
#include "softGlobal.h"
#include "softCrypt.h"
#include "softSession.h"
#include "softObject.h"
#include "softKeys.h"
#include "softKeystore.h"
#include "softKeystoreUtil.h"
#include "softMAC.h"
#include "softOps.h"

soft_session_t token_session;

/*
 * soft_gen_hashed_pin()
 *
 * Arguments:
 *
 *      pPin:   pointer to caller provided Pin
 *      result: output argument which contains the address of the
 *              pointer to the hashed pin
 *      salt:   input argument (if non-NULL), or
 *              output argument (if NULL):
 *              address of pointer to the "salt" of the hashed pin
 *
 * Description:
 *
 *      Generate a hashed pin using system provided crypt(3C) function.
 *
 * Returns:
 *
 *      0: no error
 *      -1: some error occurred while generating the hashed pin
 *
 */
int
soft_gen_hashed_pin(CK_UTF8CHAR_PTR pPin, char **result, char **salt)
{

        uid_t uid;
        struct passwd pwd, *pw;
        char pwdbuf[PWD_BUFFER_SIZE];
        boolean_t new_salt = B_FALSE;

        /*
         * We need to get the passwd entry of the application, which is required
         * by the crypt_gensalt() below.
         */
        uid = geteuid();
        if (getpwuid_r(uid, &pwd, pwdbuf, PWD_BUFFER_SIZE, &pw) != 0) {
                return (-1);
        }

        if (*salt == NULL) {
                new_salt = B_TRUE;
                /*
                 * crypt_gensalt() will allocate memory to store the new salt.
                 * on return.  Pass "$5" here to default to crypt_sha256 since
                 * SHA256 is a FIPS 140-2 certified algorithm and we shouldn't
                 * assume the system default is that strong.
                 */
                if ((*salt = crypt_gensalt("$5", pw)) == NULL) {
                        return (-1);
                }
        }

        if ((*result = crypt((char *)pPin, *salt)) == NULL) {
                if (new_salt) {
                        size_t saltlen = strlen(*salt) + 1;

                        freezero(*salt, saltlen);
                }
                return (-1);
        }

        return (0);
}

/*
 * Authenticate user's PIN for C_Login.
 */
CK_RV
soft_verify_pin(CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen)
{

        char    *user_cryptpin = NULL;
        char    *ks_cryptpin = NULL;
        char    *salt = NULL;
        uchar_t *tmp_pin = NULL;
        boolean_t pin_initialized = B_FALSE;
        CK_RV   rv = CKR_OK;
        size_t  len = 0;

        /*
         * Check to see if keystore is initialized.
         */
        rv = soft_keystore_pin_initialized(&pin_initialized, &ks_cryptpin,
            B_FALSE);
        if (rv != CKR_OK)
                return (rv);

        /*
         * Authenticate user's PIN for C_Login.
         */
        if (pin_initialized) {

                if (soft_keystore_get_pin_salt(&salt) < 0) {
                        rv = CKR_FUNCTION_FAILED;
                        goto cleanup;
                }

                /*
                 * Generate the hashed value based on the user's supplied pin.
                 */
                tmp_pin = malloc(ulPinLen + 1);
                if (tmp_pin == NULL) {
                        rv = CKR_HOST_MEMORY;
                        goto cleanup;
                }

                (void) memcpy(tmp_pin, pPin, ulPinLen);
                tmp_pin[ulPinLen] = '\0';

                if (soft_gen_hashed_pin(tmp_pin, &user_cryptpin, &salt) < 0) {
                        rv = CKR_FUNCTION_FAILED;
                        goto cleanup;
                }

                /*
                 * Compare hash value of the user supplied PIN with
                 * hash value of the keystore PIN.
                 */
                if (strcmp(user_cryptpin, ks_cryptpin) != 0) {
                        rv = CKR_PIN_INCORRECT;
                        goto cleanup;
                }

                /*
                 * Provide the user's PIN to low-level keystore so that
                 * it can use it to generate encryption key as needed for
                 * encryption/decryption of the private objects in
                 * keystore.
                 */
                if (soft_keystore_authpin(tmp_pin) != 0) {
                        rv = CKR_FUNCTION_FAILED;
                } else {
                        rv = CKR_OK;
                }
                goto cleanup;
        } else {
                /*
                 * The PIN is not initialized in the keystore
                 * We will let it pass the authentication anyway but set the
                 * "userpin_change_needed" flag so that the application
                 * will get CKR_PIN_EXPIRED by other C_functions such as
                 * C_CreateObject, C_FindObjectInit, C_GenerateKey etc.
                 */
                soft_slot.userpin_change_needed = 1;
                rv = CKR_OK;
        }

cleanup:
        if (salt) {
                len = strlen(salt) + 1;
                freezero(salt, len);
        }
        if (tmp_pin) {
                len = strlen((char *)tmp_pin) + 1;
                freezero(tmp_pin, len);
        }
        if (ks_cryptpin) {
                len = strlen(ks_cryptpin) + 1;
                freezero(ks_cryptpin, len);
        }
        return (rv);
}

/*
 * The second level C_SetPIN function.
 */
CK_RV
soft_setpin(CK_UTF8CHAR_PTR pOldPin, CK_ULONG ulOldPinLen,
    CK_UTF8CHAR_PTR pNewPin, CK_ULONG ulNewPinLen)
{

        char    *user_cryptpin = NULL;
        char    *ks_cryptpin = NULL;
        char    *salt = NULL;
        boolean_t pin_initialized = B_FALSE;
        uchar_t *tmp_old_pin = NULL, *tmp_new_pin = NULL;
        CK_RV   rv = CKR_OK;
        size_t  len = 0;

        /*
         * Check to see if keystore is initialized.
         */
        rv = soft_keystore_pin_initialized(&pin_initialized, &ks_cryptpin,
            B_FALSE);
        if (rv != CKR_OK)
                return (rv);

        /*
         * Authenticate user's PIN for C_SetPIN.
         */
        if (pin_initialized) {
                /*
                 * Generate the hashed value based on the user supplied PIN.
                 */
                if (soft_keystore_get_pin_salt(&salt) < 0) {
                        rv = CKR_FUNCTION_FAILED;
                        goto cleanup;
                }

                tmp_old_pin = malloc(ulOldPinLen + 1);
                if (tmp_old_pin == NULL) {
                        rv = CKR_HOST_MEMORY;
                        goto cleanup;
                }
                (void) memcpy(tmp_old_pin, pOldPin, ulOldPinLen);
                tmp_old_pin[ulOldPinLen] = '\0';

                if (soft_gen_hashed_pin(tmp_old_pin, &user_cryptpin,
                    &salt) < 0) {
                        rv = CKR_FUNCTION_FAILED;
                        goto cleanup;
                }

                /*
                 * Compare hashed value of the user supplied PIN with the
                 * hashed value of the keystore PIN.
                 */
                if (strcmp(user_cryptpin, ks_cryptpin) != 0) {
                        rv = CKR_PIN_INCORRECT;
                        goto cleanup;
                }
        } else {
                /*
                 * This is the first time to setpin, the oldpin must be
                 * "changeme".
                 */
                if (strncmp("changeme", (const char *)pOldPin,
                    ulOldPinLen) != 0) {
                        rv = CKR_PIN_INCORRECT;
                        goto cleanup;
                }
        }

        tmp_new_pin = malloc(ulNewPinLen + 1);
        if (tmp_new_pin == NULL) {
                rv = CKR_HOST_MEMORY;
                goto cleanup;
        }
        (void) memcpy(tmp_new_pin, pNewPin, ulNewPinLen);
        tmp_new_pin[ulNewPinLen] = '\0';

        /*
         * Set the new pin after the old pin is authenticated.
         */
        if (soft_keystore_setpin(tmp_old_pin, tmp_new_pin, B_FALSE)) {
                rv = CKR_FUNCTION_FAILED;
                goto cleanup;
        } else {
                (void) pthread_mutex_lock(&soft_giant_mutex);
                soft_slot.userpin_change_needed = 0;
                (void) pthread_mutex_unlock(&soft_giant_mutex);
                rv = CKR_OK;
        }

cleanup:
        if (salt) {
                len = strlen(salt) + 1;
                freezero(salt, len);
        }
        if (ks_cryptpin) {
                len = strlen(ks_cryptpin) + 1;
                freezero(ks_cryptpin, len);
        }
        if (tmp_old_pin) {
                len = strlen((char *)tmp_old_pin) + 1;
                freezero(tmp_old_pin, len);
        }
        if (tmp_new_pin) {
                len = strlen((char *)tmp_new_pin) + 1;
                freezero(tmp_new_pin, len);
        }

        return (rv);
}

/*
 * soft_keystore_pack_obj()
 *
 * Arguments:
 *
 *      obj:    pointer to the soft_object_t of the token object to
 *              be packed
 *      ks_buf: output argument which contains the address of the
 *              pointer to the buf of the packed token object
 *              soft_keystore_pack_obj() will allocate memory for the buf,
 *              it is caller's responsibility to free it.
 *      len:    output argument which contains the address of the
 *              buffer length of the packed token object
 *
 * Description:
 *
 *      Pack the in-core token object into the keystore format.
 *
 * Returns:
 *
 *      CKR_OK: no error
 *      Other: some error occurred while packing the object
 *
 */
CK_RV
soft_keystore_pack_obj(soft_object_t *obj, uchar_t **ks_buf, size_t *len)
{
        ks_obj_hdr_t hdr;
        ks_attr_hdr_t attr_hdr;
        CK_ATTRIBUTE_INFO_PTR extra_attr;
        int num_attrs = 0;
        ulong_t len_attrs = 0;
        size_t ks_len;
        uchar_t *buf, *buf1;
        CK_RV rv;
        int i;

        (void) memset(&hdr, 0, sizeof (ks_obj_hdr_t));

        /*
         * The first part of the packed format contains
         * the ks_obj_hdr_t struct.
         */
        hdr.class = SWAP64((uint64_t)obj->class);
        hdr.key_type = SWAP64((uint64_t)obj->key_type);
        hdr.cert_type = SWAP64((uint64_t)obj->cert_type);
        hdr.bool_attr_mask = SWAP64(obj->bool_attr_mask);
        hdr.mechanism = SWAP64((uint64_t)obj->mechanism);
        hdr.object_type = obj->object_type;

        /*
         * The second part of the packed format contains
         * the attributes from the extra atrribute list.
         */
        extra_attr = obj->extra_attrlistp;

        while (extra_attr) {
                num_attrs++;
                len_attrs += ROUNDUP(extra_attr->attr.ulValueLen, 8);
                extra_attr = extra_attr->next;
        }
        hdr.num_attrs = SWAP32(num_attrs);
        ks_len = soft_pack_object_size(obj);
        ks_len += sizeof (ks_obj_hdr_t) + len_attrs +
            2 * num_attrs * sizeof (uint64_t);
        buf = calloc(1, ks_len);
        if (buf == NULL) {
                return (CKR_HOST_MEMORY);
        }
        (void) memcpy(buf, &hdr, sizeof (ks_obj_hdr_t));
        buf1 = buf + sizeof (ks_obj_hdr_t);
        extra_attr = obj->extra_attrlistp;
        for (i = 0; i < num_attrs; i++) {
                attr_hdr.type = SWAP64((uint64_t)extra_attr->attr.type);
                attr_hdr.ulValueLen =
                    SWAP64((uint64_t)extra_attr->attr.ulValueLen);
                (void) memcpy(buf1, &attr_hdr, sizeof (ks_attr_hdr_t));
                buf1 = buf1 + sizeof (ks_attr_hdr_t);
                (void) memcpy(buf1, extra_attr->attr.pValue,
                    extra_attr->attr.ulValueLen);
                buf1 = buf1 + ROUNDUP(extra_attr->attr.ulValueLen, 8);
                extra_attr = extra_attr->next;
        }

        /*
         * The third part of the packed format contains
         * the key itself.
         */
        rv = soft_pack_object(obj, buf1);
        *len = ks_len;
        *ks_buf = buf;

        return (rv);

}

/*
 * soft_keystore_unpack_obj()
 *
 * Arguments:
 *
 *      obj:    pointer to the soft_object_t to store the unpacked
 *              token object
 *      ks_obj: input argument which contains the pointer to the
 *              ks_obj_t struct of packed token object to be unpacked
 *
 * Description:
 *
 *      Unpack the token object in keystore format to in-core soft_object_t.
 *
 * Returns:
 *
 *      CKR_OK: no error
 *      Other: some error occurred while unpacking the object
 *
 */
CK_RV
soft_keystore_unpack_obj(soft_object_t *obj, ks_obj_t *ks_obj)
{

        CK_RV rv;
        ks_obj_hdr_t *hdr;
        ks_attr_hdr_t *attr_hdr;
        CK_ATTRIBUTE template;
        int i;
        uchar_t *buf;

        /*
         * Unpack the common area.
         */
        (void) strcpy((char *)obj->ks_handle.name,
            (char *)ks_obj->ks_handle.name);
        obj->ks_handle.public = ks_obj->ks_handle.public;
        /* LINTED: pointer alignment */
        hdr = (ks_obj_hdr_t *)ks_obj->buf;
        obj->version = ks_obj->obj_version;
        obj->class = (CK_OBJECT_CLASS)(SWAP64(hdr->class));
        obj->key_type = (CK_KEY_TYPE)(SWAP64(hdr->key_type));
        obj->cert_type = (CK_CERTIFICATE_TYPE)(SWAP64(hdr->cert_type));
        obj->bool_attr_mask = SWAP64(hdr->bool_attr_mask);
        obj->mechanism = (CK_MECHANISM_TYPE)(SWAP64(hdr->mechanism));
        obj->object_type = hdr->object_type;

        /*
         * Initialize other stuffs which were not from keystore.
         */
        (void) pthread_mutex_init(&obj->object_mutex, NULL);
        obj->magic_marker = SOFTTOKEN_OBJECT_MAGIC;
        obj->session_handle = (CK_SESSION_HANDLE)NULL;

        buf = ks_obj->buf + sizeof (ks_obj_hdr_t);

        /*
         * Unpack extra attribute list.
         */
        for (i = 0; i < SWAP32(hdr->num_attrs); i++) {
                /* LINTED: pointer alignment */
                attr_hdr = (ks_attr_hdr_t *)buf;
                (void) memset(&template, 0, sizeof (CK_ATTRIBUTE));
                template.type = (CK_ATTRIBUTE_TYPE)(SWAP64(attr_hdr->type));
                template.ulValueLen = (CK_ULONG)(SWAP64(attr_hdr->ulValueLen));
                buf = buf + sizeof (ks_attr_hdr_t);
                /* Allocate storage for the value of the attribute. */
                if (template.ulValueLen > 0) {
                        template.pValue = malloc(template.ulValueLen);
                        if (template.pValue == NULL) {
                                return (CKR_HOST_MEMORY);
                        }
                        (void) memcpy(template.pValue, buf,
                            template.ulValueLen);
                }

                rv = soft_add_extra_attr(&template, obj);
                freezero(template.pValue, template.ulValueLen);

                if (rv != CKR_OK) {
                        return (rv);
                }

                buf = buf + ROUNDUP(template.ulValueLen, 8);
        }

        /*
         * Unpack the key itself.
         */
        rv = soft_unpack_object(obj, buf);
        return (rv);

}


/*
 * soft_unpack_obj_attribute()
 *
 * Arguments:
 *
 *      buf:    contains the packed data (attributes) from keystore
 *      key_dest: the key attribute will be unpacked and save in key_dest
 *      cert_dest: the certificate attribute will be unpacked an
 *                 in cert_dest
 *      offset: length of the current attribute occupies.
 *              The caller should use this returned "offset" to
 *              advance the buffer pointer to next attribute.
 *      cert:   TRUE for certificate (use cert_dest)
 *              FALSE for key (use key_dest)
 *
 * Description:
 *
 *      Unpack the attribute from keystore format to the big integer format.
 *
 * Returns:
 *
 *      CKR_OK: no error
 *      Other: some error occurred while unpacking the object attribute
 *
 */
CK_RV
soft_unpack_obj_attribute(uchar_t *buf, biginteger_t *key_dest,
    cert_attr_t **cert_dest, ulong_t *offset, boolean_t cert)
{

        CK_RV rv;
        CK_ATTRIBUTE template;

        /* LINTED: pointer alignment */
        template.ulValueLen = SWAP64(*(uint64_t *)buf);
        buf = buf + sizeof (uint64_t);
        template.pValue = malloc(template.ulValueLen);
        if (template.pValue == NULL) {
                return (CKR_HOST_MEMORY);
        }

        (void) memcpy(template.pValue, buf, template.ulValueLen);
        if (cert) {
                rv = get_cert_attr_from_template(cert_dest, &template);
        } else {
                rv = get_bigint_attr_from_template(key_dest, &template);
        }

        freezero(template.pValue, template.ulValueLen);
        if (rv != CKR_OK) {
                return (rv);
        }

        *offset = sizeof (uint64_t) + template.ulValueLen;
        return (CKR_OK);
}


/*
 * Calculate the total buffer length required to store the
 * object key (the third part) in a keystore format.
 */
ulong_t
soft_pack_object_size(soft_object_t *objp)
{

        CK_OBJECT_CLASS class = objp->class;
        CK_KEY_TYPE     keytype = objp->key_type;
        CK_CERTIFICATE_TYPE certtype = objp->cert_type;

        switch (class) {
        case CKO_PUBLIC_KEY:
                switch (keytype) {
                case CKK_RSA:
                        /*
                         * modulus_bits + modulus_len + modulus +
                         * pubexpo_len + pubexpo
                         */
                        return (ROUNDUP(((biginteger_t *)
                            OBJ_PUB_RSA_MOD(objp))->big_value_len, 8) +
                            ROUNDUP(((biginteger_t *)
                            OBJ_PUB_RSA_PUBEXPO(objp))->big_value_len, 8) +
                            3 * sizeof (uint64_t));

                case CKK_DSA:
                        /*
                         * prime_len + prime + subprime_len + subprime +
                         * base_len + base + value_len + value
                         */
                        return (ROUNDUP(((biginteger_t *)
                            OBJ_PUB_DSA_PRIME(objp))->big_value_len, 8) +
                            ROUNDUP(((biginteger_t *)
                            OBJ_PUB_DSA_SUBPRIME(objp))->big_value_len, 8) +
                            ROUNDUP(((biginteger_t *)
                            OBJ_PUB_DSA_BASE(objp))->big_value_len, 8) +
                            ROUNDUP(((biginteger_t *)
                            OBJ_PUB_DSA_VALUE(objp))->big_value_len, 8) +
                            4 * sizeof (uint64_t));
                case CKK_EC:
                        /*
                         * ec_point_len + ec_point
                         */
                        return (ROUNDUP(((biginteger_t *)
                            OBJ_PUB_EC_POINT(objp))->big_value_len, 8) +
                            sizeof (uint64_t));
                case CKK_DH:
                        /*
                         * prime_len + prime + base_len + base +
                         * value_len + value
                         */
                        return (ROUNDUP(((biginteger_t *)
                            OBJ_PUB_DH_PRIME(objp))->big_value_len, 8) +
                            ROUNDUP(((biginteger_t *)
                            OBJ_PUB_DH_BASE(objp))->big_value_len, 8) +
                            ROUNDUP(((biginteger_t *)
                            OBJ_PUB_DH_VALUE(objp))->big_value_len, 8) +
                            3 * sizeof (uint64_t));

                case CKK_X9_42_DH:
                        /*
                         * prime_len + prime + base_len + base +
                         * subprime_len + subprime + value_len + value
                         */
                        return (ROUNDUP(((biginteger_t *)
                            OBJ_PUB_DH942_PRIME(objp))->big_value_len, 8) +
                            ROUNDUP(((biginteger_t *)
                            OBJ_PUB_DH942_BASE(objp))->big_value_len, 8) +
                            ROUNDUP(((biginteger_t *)
                            OBJ_PUB_DH942_SUBPRIME(objp))->big_value_len, 8) +
                            ROUNDUP(((biginteger_t *)
                            OBJ_PUB_DH942_VALUE(objp))->big_value_len, 8) +
                            4 * sizeof (uint64_t));
                } /* keytype */

                break;

        case CKO_PRIVATE_KEY:
                switch (keytype) {
                case CKK_RSA:
                        /*
                         * modulus_len + modulus + pubexpo_len + pubexpo +
                         * priexpo_len + priexpo + prime1_len + prime1 +
                         * prime2_len + prime2 + expo1_len + expo1 +
                         * expo2_len + expo2 + coef_len + coef
                         */
                        return (ROUNDUP(((biginteger_t *)
                            OBJ_PRI_RSA_MOD(objp))->big_value_len, 8) +
                            ROUNDUP(((biginteger_t *)
                            OBJ_PRI_RSA_PUBEXPO(objp))->big_value_len, 8) +
                            ROUNDUP(((biginteger_t *)
                            OBJ_PRI_RSA_PRIEXPO(objp))->big_value_len, 8) +
                            ROUNDUP(((biginteger_t *)
                            OBJ_PRI_RSA_PRIME1(objp))->big_value_len, 8) +
                            ROUNDUP(((biginteger_t *)
                            OBJ_PRI_RSA_PRIME2(objp))->big_value_len, 8) +
                            ROUNDUP(((biginteger_t *)
                            OBJ_PRI_RSA_EXPO1(objp))->big_value_len, 8) +
                            ROUNDUP(((biginteger_t *)
                            OBJ_PRI_RSA_EXPO2(objp))->big_value_len, 8) +
                            ROUNDUP(((biginteger_t *)
                            OBJ_PRI_RSA_COEF(objp))->big_value_len, 8) +
                            8 * sizeof (uint64_t));

                case CKK_DSA:
                        /*
                         * prime_len + prime + subprime_len + subprime +
                         * base_len + base + value_len + value
                         */
                        return (ROUNDUP(((biginteger_t *)
                            OBJ_PRI_DSA_PRIME(objp))->big_value_len, 8) +
                            ROUNDUP(((biginteger_t *)
                            OBJ_PRI_DSA_SUBPRIME(objp))->big_value_len, 8) +
                            ROUNDUP(((biginteger_t *)
                            OBJ_PRI_DSA_BASE(objp))->big_value_len, 8) +
                            ROUNDUP(((biginteger_t *)
                            OBJ_PRI_DSA_VALUE(objp))->big_value_len, 8) +
                            4 * sizeof (uint64_t));

                case CKK_DH:
                        /*
                         * value_bits + prime_len + prime + base_len + base +
                         * value_len + value
                         */
                        return (ROUNDUP(((biginteger_t *)
                            OBJ_PRI_DH_PRIME(objp))->big_value_len, 8) +
                            ROUNDUP(((biginteger_t *)
                            OBJ_PRI_DH_BASE(objp))->big_value_len, 8) +
                            ROUNDUP(((biginteger_t *)
                            OBJ_PRI_DH_VALUE(objp))->big_value_len, 8) +
                            4 * sizeof (uint64_t));

                case CKK_EC:
                        /*
                         * value_len + value
                         */
                        return (ROUNDUP(((biginteger_t *)
                            OBJ_PRI_EC_VALUE(objp))->big_value_len, 8) +
                            sizeof (uint64_t));

                case CKK_X9_42_DH:
                        /*
                         * prime_len + prime + base_len + base +
                         * subprime_len + subprime + value_len + value
                         */
                        return (ROUNDUP(((biginteger_t *)
                            OBJ_PRI_DH942_PRIME(objp))->big_value_len, 8) +
                            ROUNDUP(((biginteger_t *)
                            OBJ_PRI_DH942_BASE(objp))->big_value_len, 8) +
                            ROUNDUP(((biginteger_t *)
                            OBJ_PRI_DH942_SUBPRIME(objp))->big_value_len, 8) +
                            ROUNDUP(((biginteger_t *)
                            OBJ_PRI_DH942_VALUE(objp))->big_value_len, 8) +
                            4 * sizeof (uint64_t));

                } /* keytype */

                break;

        case CKO_SECRET_KEY:
                /*
                 * value_len + value
                 */
                return (ROUNDUP(OBJ_SEC_VALUE_LEN(objp), 8) +
                    sizeof (uint64_t));

        case CKO_CERTIFICATE:
                switch (certtype) {
                case CKC_X_509:
                        /*
                         * subject_len + subject + value_len + value
                         */
                        return (ROUNDUP(((cert_attr_t *)
                            X509_CERT_SUBJECT(objp))->length, 8) +
                            ROUNDUP(((cert_attr_t *)
                            X509_CERT_VALUE(objp))->length, 8) +
                            2 * sizeof (uint64_t));

                case CKC_X_509_ATTR_CERT:
                        /*
                         * owner_len + owner + value_len + value
                         */
                        return (ROUNDUP(((cert_attr_t *)
                            X509_ATTR_CERT_OWNER(objp))->length, 8) +
                            ROUNDUP(((cert_attr_t *)
                            X509_ATTR_CERT_VALUE(objp))->length, 8) +
                            2 * sizeof (uint64_t));
                }
                return (0);

        case CKO_DOMAIN_PARAMETERS:

                return (0);
        }
        return (0);
}

/*
 * Pack the object key (the third part) from the soft_object_t
 * into the keystore format.
 */
CK_RV
soft_pack_object(soft_object_t *objp, uchar_t *buf)
{

        CK_OBJECT_CLASS class = objp->class;
        CK_KEY_TYPE     keytype = objp->key_type;
        CK_CERTIFICATE_TYPE certtype = objp->cert_type;
        uint64_t tmp_val;

        switch (class) {
        case CKO_PUBLIC_KEY:
                switch (keytype) {
                case CKK_RSA:
                        /* modulus_bits */
                        tmp_val = SWAP64((uint64_t)OBJ_PUB_RSA_MOD_BITS(objp));
                        (void) memcpy(buf, (char *)&tmp_val, sizeof (uint64_t));
                        buf = buf + sizeof (uint64_t);

                        /* modulus_len + modulus */
                        tmp_val = SWAP64((uint64_t)(((biginteger_t *)
                            OBJ_PUB_RSA_MOD(objp))->big_value_len));
                        (void) memcpy(buf, (char *)&tmp_val, sizeof (uint64_t));
                        buf = buf + sizeof (uint64_t);

                        (void) memcpy(buf, (char *)(((biginteger_t *)
                            OBJ_PUB_RSA_MOD(objp))->big_value),
                            ((biginteger_t *)
                            OBJ_PUB_RSA_MOD(objp))->big_value_len);
                        buf = buf + ROUNDUP(((biginteger_t *)
                            OBJ_PUB_RSA_MOD(objp))->big_value_len, 8);

                        /* pubexpo_len + pubexpo */
                        tmp_val = SWAP64((uint64_t)((biginteger_t *)
                            OBJ_PUB_RSA_PUBEXPO(objp))->big_value_len);
                        (void) memcpy(buf, (char *)&tmp_val, sizeof (uint64_t));
                        buf = buf + sizeof (uint64_t);

                        (void) memcpy(buf, (char *)(((biginteger_t *)
                            OBJ_PUB_RSA_PUBEXPO(objp))->big_value),
                            ((biginteger_t *)
                            OBJ_PUB_RSA_PUBEXPO(objp))->big_value_len);
                        break;

                case CKK_DSA:
                        /* prime_len + prime */
                        tmp_val = SWAP64((uint64_t)((biginteger_t *)
                            OBJ_PUB_DSA_PRIME(objp))->big_value_len);
                        (void) memcpy(buf, (char *)&tmp_val, sizeof (uint64_t));
                        buf = buf + sizeof (uint64_t);

                        (void) memcpy(buf, (char *)((biginteger_t *)
                            OBJ_PUB_DSA_PRIME(objp))->big_value,
                            ((biginteger_t *)
                            OBJ_PUB_DSA_PRIME(objp))->big_value_len);
                        buf = buf + ROUNDUP(((biginteger_t *)
                            OBJ_PUB_DSA_PRIME(objp))->big_value_len, 8);

                        /* subprime_len + subprime */
                        tmp_val = SWAP64((uint64_t)((biginteger_t *)
                            OBJ_PUB_DSA_SUBPRIME(objp))->big_value_len);
                        (void) memcpy(buf, (char *)&tmp_val, sizeof (uint64_t));
                        buf = buf + sizeof (uint64_t);

                        (void) memcpy(buf, (char *)((biginteger_t *)
                            OBJ_PUB_DSA_SUBPRIME(objp))->big_value,
                            ((biginteger_t *)
                            OBJ_PUB_DSA_SUBPRIME(objp))->big_value_len);
                        buf = buf + ROUNDUP(((biginteger_t *)
                            OBJ_PUB_DSA_SUBPRIME(objp))->big_value_len, 8);

                        /* base_len + base */
                        tmp_val = SWAP64((uint64_t)((biginteger_t *)
                            OBJ_PUB_DSA_BASE(objp))->big_value_len);
                        (void) memcpy(buf, (char *)&tmp_val, sizeof (uint64_t));
                        buf = buf + sizeof (uint64_t);

                        (void) memcpy(buf, (char *)((biginteger_t *)
                            OBJ_PUB_DSA_BASE(objp))->big_value,
                            ((biginteger_t *)
                            OBJ_PUB_DSA_BASE(objp))->big_value_len);
                        buf = buf + ROUNDUP(((biginteger_t *)
                            OBJ_PUB_DSA_BASE(objp))->big_value_len, 8);

                        /* value_len + value */
                        tmp_val = SWAP64((uint64_t)((biginteger_t *)
                            OBJ_PUB_DSA_VALUE(objp))->big_value_len);
                        (void) memcpy(buf, (char *)&tmp_val, sizeof (uint64_t));
                        buf = buf + sizeof (uint64_t);

                        (void) memcpy(buf, (char *)((biginteger_t *)
                            OBJ_PUB_DSA_VALUE(objp))->big_value,
                            ((biginteger_t *)
                            OBJ_PUB_DSA_VALUE(objp))->big_value_len);

                        break;
                case CKK_EC:
                        /* point_len + point */
                        tmp_val = SWAP64((uint64_t)((biginteger_t *)
                            OBJ_PUB_EC_POINT(objp))->big_value_len);
                        (void) memcpy(buf, (char *)&tmp_val, sizeof (uint64_t));
                        buf = buf + sizeof (uint64_t);

                        (void) memcpy(buf, (char *)((biginteger_t *)
                            OBJ_PUB_EC_POINT(objp))->big_value,
                            ((biginteger_t *)
                            OBJ_PUB_EC_POINT(objp))->big_value_len);
                        break;

                case CKK_DH:
                        /* prime_len + prime */
                        tmp_val = SWAP64((uint64_t)((biginteger_t *)
                            OBJ_PUB_DH_PRIME(objp))->big_value_len);
                        (void) memcpy(buf, (char *)&tmp_val, sizeof (uint64_t));
                        buf = buf + sizeof (uint64_t);

                        (void) memcpy(buf, (char *)((biginteger_t *)
                            OBJ_PUB_DH_PRIME(objp))->big_value,
                            ((biginteger_t *)
                            OBJ_PUB_DH_PRIME(objp))->big_value_len);
                        buf = buf + ROUNDUP(((biginteger_t *)
                            OBJ_PUB_DH_PRIME(objp))->big_value_len, 8);

                        /* base_len + base */
                        tmp_val = SWAP64((uint64_t)((biginteger_t *)
                            OBJ_PUB_DH_BASE(objp))->big_value_len);
                        (void) memcpy(buf, (char *)&tmp_val, sizeof (uint64_t));
                        buf = buf + sizeof (uint64_t);

                        (void) memcpy(buf, (char *)((biginteger_t *)
                            OBJ_PUB_DH_BASE(objp))->big_value,
                            ((biginteger_t *)
                            OBJ_PUB_DH_BASE(objp))->big_value_len);
                        buf = buf + ROUNDUP(((biginteger_t *)
                            OBJ_PUB_DH_BASE(objp))->big_value_len, 8);

                        /* value_len + value */
                        tmp_val = SWAP64((uint64_t)((biginteger_t *)
                            OBJ_PUB_DH_VALUE(objp))->big_value_len);
                        (void) memcpy(buf, (char *)&tmp_val, sizeof (uint64_t));
                        buf = buf + sizeof (uint64_t);

                        (void) memcpy(buf, (char *)((biginteger_t *)
                            OBJ_PUB_DH_VALUE(objp))->big_value,
                            ((biginteger_t *)
                            OBJ_PUB_DH_VALUE(objp))->big_value_len);

                        break;

                case CKK_X9_42_DH:
                        /* prime_len +  prime */
                        tmp_val = SWAP64((uint64_t)((biginteger_t *)
                            OBJ_PUB_DH942_PRIME(objp))->big_value_len);
                        (void) memcpy(buf, (char *)&tmp_val, sizeof (uint64_t));
                        buf = buf + sizeof (uint64_t);

                        (void) memcpy(buf, (char *)((biginteger_t *)
                            OBJ_PUB_DH942_PRIME(objp))->big_value,
                            ((biginteger_t *)
                            OBJ_PUB_DH942_PRIME(objp))->big_value_len);
                        buf = buf + ROUNDUP(((biginteger_t *)
                            OBJ_PUB_DH942_PRIME(objp))->big_value_len, 8);

                        /* base_len + base */
                        tmp_val = SWAP64((uint64_t)((biginteger_t *)
                            OBJ_PUB_DH942_BASE(objp))->big_value_len);
                        (void) memcpy(buf, (char *)&tmp_val, sizeof (uint64_t));
                        buf = buf + sizeof (uint64_t);

                        (void) memcpy(buf, (char *)((biginteger_t *)
                            OBJ_PUB_DH942_BASE(objp))->big_value,
                            ((biginteger_t *)
                            OBJ_PUB_DH942_BASE(objp))->big_value_len);
                        buf = buf + ROUNDUP(((biginteger_t *)
                            OBJ_PUB_DH942_BASE(objp))->big_value_len, 8);

                        /* subprime_len + subprime */
                        tmp_val = SWAP64((uint64_t)((biginteger_t *)
                            OBJ_PUB_DH942_SUBPRIME(objp))->big_value_len);
                        (void) memcpy(buf, (char *)&tmp_val, sizeof (uint64_t));
                        buf = buf + sizeof (uint64_t);

                        (void) memcpy(buf, (char *)((biginteger_t *)
                            OBJ_PUB_DH942_SUBPRIME(objp))->big_value,
                            ((biginteger_t *)
                            OBJ_PUB_DH942_SUBPRIME(objp))->big_value_len);
                        buf = buf + ROUNDUP(((biginteger_t *)
                            OBJ_PUB_DH942_SUBPRIME(objp))->big_value_len, 8);

                        /* value_len + value */
                        tmp_val = SWAP64((uint64_t)((biginteger_t *)
                            OBJ_PUB_DH942_VALUE(objp))->big_value_len);
                        (void) memcpy(buf, (char *)&tmp_val, sizeof (uint64_t));
                        buf = buf + sizeof (uint64_t);

                        (void) memcpy(buf, (char *)((biginteger_t *)
                            OBJ_PUB_DH942_VALUE(objp))->big_value,
                            ((biginteger_t *)
                            OBJ_PUB_DH942_VALUE(objp))->big_value_len);

                        break;
                } /* keytype */

                break;

        case CKO_PRIVATE_KEY:
                switch (keytype) {
                case CKK_RSA:
                        /* modulus_len + modulus */
                        tmp_val = SWAP64((uint64_t)((biginteger_t *)
                            OBJ_PRI_RSA_MOD(objp))->big_value_len);
                        (void) memcpy(buf, (char *)&tmp_val, sizeof (uint64_t));
                        buf = buf + sizeof (uint64_t);

                        (void) memcpy(buf, (char *)((biginteger_t *)
                            OBJ_PRI_RSA_MOD(objp))->big_value,
                            ((biginteger_t *)
                            OBJ_PRI_RSA_MOD(objp))->big_value_len);
                        buf = buf + ROUNDUP(((biginteger_t *)
                            OBJ_PRI_RSA_MOD(objp))->big_value_len, 8);

                        /* pubexpo_len + pubexpo */
                        tmp_val = SWAP64((uint64_t)((biginteger_t *)
                            OBJ_PRI_RSA_PUBEXPO(objp))->big_value_len);
                        (void) memcpy(buf, (char *)&tmp_val, sizeof (uint64_t));
                        buf = buf + sizeof (uint64_t);

                        (void) memcpy(buf, (char *)((biginteger_t *)
                            OBJ_PRI_RSA_PUBEXPO(objp))->big_value,
                            ((biginteger_t *)
                            OBJ_PRI_RSA_PUBEXPO(objp))->big_value_len);
                        buf = buf + ROUNDUP(((biginteger_t *)
                            OBJ_PRI_RSA_PUBEXPO(objp))->big_value_len, 8);

                        /* priexpo_len + priexpo */
                        tmp_val = SWAP64((uint64_t)((biginteger_t *)
                            OBJ_PRI_RSA_PRIEXPO(objp))->big_value_len);
                        (void) memcpy(buf, (char *)&tmp_val, sizeof (uint64_t));
                        buf = buf + sizeof (uint64_t);

                        (void) memcpy(buf, (char *)((biginteger_t *)
                            OBJ_PRI_RSA_PRIEXPO(objp))->big_value,
                            ((biginteger_t *)
                            OBJ_PRI_RSA_PRIEXPO(objp))->big_value_len);
                        buf = buf + ROUNDUP(((biginteger_t *)
                            OBJ_PRI_RSA_PRIEXPO(objp))->big_value_len, 8);

                        /* prime1_len + prime1 */
                        tmp_val = SWAP64((uint64_t)((biginteger_t *)
                            OBJ_PRI_RSA_PRIME1(objp))->big_value_len);
                        (void) memcpy(buf, (char *)&tmp_val, sizeof (uint64_t));
                        buf = buf + sizeof (uint64_t);

                        (void) memcpy(buf, (char *)((biginteger_t *)
                            OBJ_PRI_RSA_PRIME1(objp))->big_value,
                            ((biginteger_t *)
                            OBJ_PRI_RSA_PRIME1(objp))->big_value_len);
                        buf = buf + ROUNDUP(((biginteger_t *)
                            OBJ_PRI_RSA_PRIME1(objp))->big_value_len, 8);

                        /* prime2_len + prime2 */
                        tmp_val = SWAP64((uint64_t)((biginteger_t *)
                            OBJ_PRI_RSA_PRIME2(objp))->big_value_len);
                        (void) memcpy(buf, (char *)&tmp_val, sizeof (uint64_t));
                        buf = buf + sizeof (uint64_t);

                        (void) memcpy(buf, (char *)((biginteger_t *)
                            OBJ_PRI_RSA_PRIME2(objp))->big_value,
                            ((biginteger_t *)
                            OBJ_PRI_RSA_PRIME2(objp))->big_value_len);
                        buf = buf + ROUNDUP(((biginteger_t *)
                            OBJ_PRI_RSA_PRIME2(objp))->big_value_len, 8);

                        /* expo1_len + expo1 */
                        tmp_val = SWAP64((uint64_t)((biginteger_t *)
                            OBJ_PRI_RSA_EXPO1(objp))->big_value_len);
                        (void) memcpy(buf, (char *)&tmp_val, sizeof (uint64_t));
                        buf = buf + sizeof (uint64_t);

                        (void) memcpy(buf, (char *)((biginteger_t *)
                            OBJ_PRI_RSA_EXPO1(objp))->big_value,
                            ((biginteger_t *)
                            OBJ_PRI_RSA_EXPO1(objp))->big_value_len);
                        buf = buf + ROUNDUP(((biginteger_t *)
                            OBJ_PRI_RSA_EXPO1(objp))->big_value_len, 8);

                        /* expo2_len + expo2 */
                        tmp_val = SWAP64((uint64_t)((biginteger_t *)
                            OBJ_PRI_RSA_EXPO2(objp))->big_value_len);
                        (void) memcpy(buf, (char *)&tmp_val, sizeof (uint64_t));
                        buf = buf + sizeof (uint64_t);

                        (void) memcpy(buf, (char *)((biginteger_t *)
                            OBJ_PRI_RSA_EXPO2(objp))->big_value,
                            ((biginteger_t *)
                            OBJ_PRI_RSA_EXPO2(objp))->big_value_len);
                        buf = buf + ROUNDUP(((biginteger_t *)
                            OBJ_PRI_RSA_EXPO2(objp))->big_value_len, 8);

                        /* coef_len + coef */
                        tmp_val = SWAP64((uint64_t)((biginteger_t *)
                            OBJ_PRI_RSA_COEF(objp))->big_value_len);
                        (void) memcpy(buf, (char *)&tmp_val, sizeof (uint64_t));
                        buf = buf + sizeof (uint64_t);

                        (void) memcpy(buf, (char *)((biginteger_t *)
                            OBJ_PRI_RSA_COEF(objp))->big_value,
                            ((biginteger_t *)
                            OBJ_PRI_RSA_COEF(objp))->big_value_len);
                        buf = buf + ROUNDUP(((biginteger_t *)
                            OBJ_PRI_RSA_COEF(objp))->big_value_len, 8);

                        break;

                case CKK_DSA:
                        /* prime_len + prime */
                        tmp_val = SWAP64((uint64_t)((biginteger_t *)
                            OBJ_PRI_DSA_PRIME(objp))->big_value_len);
                        (void) memcpy(buf, (char *)&tmp_val, sizeof (uint64_t));
                        buf = buf + sizeof (uint64_t);

                        (void) memcpy(buf, (char *)((biginteger_t *)
                            OBJ_PRI_DSA_PRIME(objp))->big_value,
                            ((biginteger_t *)
                            OBJ_PRI_DSA_PRIME(objp))->big_value_len);
                        buf = buf + ROUNDUP(((biginteger_t *)
                            OBJ_PRI_DSA_PRIME(objp))->big_value_len, 8);

                        /* subprime_len + subprime */
                        tmp_val = SWAP64((uint64_t)((biginteger_t *)
                            OBJ_PRI_DSA_SUBPRIME(objp))->big_value_len);
                        (void) memcpy(buf, (char *)&tmp_val, sizeof (uint64_t));
                        buf = buf + sizeof (uint64_t);

                        (void) memcpy(buf, (char *)((biginteger_t *)
                            OBJ_PRI_DSA_SUBPRIME(objp))->big_value,
                            ((biginteger_t *)
                            OBJ_PRI_DSA_SUBPRIME(objp))->big_value_len);
                        buf = buf + ROUNDUP(((biginteger_t *)
                            OBJ_PRI_DSA_SUBPRIME(objp))->big_value_len, 8);

                        /* base_len + base */
                        tmp_val = SWAP64((uint64_t)((biginteger_t *)
                            OBJ_PRI_DSA_BASE(objp))->big_value_len);
                        (void) memcpy(buf, (char *)&tmp_val, sizeof (uint64_t));
                        buf = buf + sizeof (uint64_t);

                        (void) memcpy(buf, (char *)((biginteger_t *)
                            OBJ_PRI_DSA_BASE(objp))->big_value,
                            ((biginteger_t *)
                            OBJ_PRI_DSA_BASE(objp))->big_value_len);
                        buf = buf + ROUNDUP(((biginteger_t *)
                            OBJ_PRI_DSA_BASE(objp))->big_value_len, 8);

                        /* value_len + value */
                        tmp_val = SWAP64((uint64_t)((biginteger_t *)
                            OBJ_PRI_DSA_VALUE(objp))->big_value_len);
                        (void) memcpy(buf, (char *)&tmp_val, sizeof (uint64_t));
                        buf = buf + sizeof (uint64_t);

                        (void) memcpy(buf, (char *)((biginteger_t *)
                            OBJ_PRI_DSA_VALUE(objp))->big_value,
                            ((biginteger_t *)
                            OBJ_PRI_DSA_VALUE(objp))->big_value_len);

                        break;
                case CKK_EC:
                        /* value_len + value */
                        tmp_val = SWAP64((uint64_t)((biginteger_t *)
                            OBJ_PRI_EC_VALUE(objp))->big_value_len);
                        (void) memcpy(buf, (char *)&tmp_val, sizeof (uint64_t));
                        buf = buf + sizeof (uint64_t);

                        (void) memcpy(buf, (char *)((biginteger_t *)
                            OBJ_PRI_EC_VALUE(objp))->big_value,
                            ((biginteger_t *)
                            OBJ_PRI_EC_VALUE(objp))->big_value_len);
                        break;

                case CKK_DH:
                        /* value_bits */
                        tmp_val = SWAP64((uint64_t)OBJ_PRI_DH_VAL_BITS(objp));
                        (void) memcpy(buf, (char *)&tmp_val, sizeof (uint64_t));
                        buf = buf + sizeof (uint64_t);

                        /* prime_len + prime */
                        tmp_val = SWAP64((uint64_t)((biginteger_t *)
                            OBJ_PRI_DH_PRIME(objp))->big_value_len);
                        (void) memcpy(buf, (char *)&tmp_val, sizeof (uint64_t));
                        buf = buf + sizeof (uint64_t);

                        (void) memcpy(buf, (char *)((biginteger_t *)
                            OBJ_PRI_DH_PRIME(objp))->big_value,
                            ((biginteger_t *)
                            OBJ_PRI_DH_PRIME(objp))->big_value_len);
                        buf = buf + ROUNDUP(((biginteger_t *)
                            OBJ_PRI_DH_PRIME(objp))->big_value_len, 8);

                        /* base_len + base */
                        tmp_val = SWAP64((uint64_t)((biginteger_t *)
                            OBJ_PRI_DH_BASE(objp))->big_value_len);
                        (void) memcpy(buf, (char *)&tmp_val, sizeof (uint64_t));
                        buf = buf + sizeof (uint64_t);

                        (void) memcpy(buf, (char *)((biginteger_t *)
                            OBJ_PRI_DH_BASE(objp))->big_value,
                            ((biginteger_t *)
                            OBJ_PRI_DH_BASE(objp))->big_value_len);
                        buf = buf + ROUNDUP(((biginteger_t *)
                            OBJ_PRI_DH_BASE(objp))->big_value_len, 8);

                        /* value_len + value */
                        tmp_val = SWAP64((uint64_t)((biginteger_t *)
                            OBJ_PRI_DH_VALUE(objp))->big_value_len);
                        (void) memcpy(buf, (char *)&tmp_val, sizeof (uint64_t));
                        buf = buf + sizeof (uint64_t);

                        (void) memcpy(buf, (char *)((biginteger_t *)
                            OBJ_PRI_DH_VALUE(objp))->big_value,
                            ((biginteger_t *)
                            OBJ_PRI_DH_VALUE(objp))->big_value_len);

                        break;

                case CKK_X9_42_DH:
                        /* prime_len + prime */
                        tmp_val = SWAP64((uint64_t)((biginteger_t *)
                            OBJ_PRI_DH942_PRIME(objp))->big_value_len);
                        (void) memcpy(buf, (char *)&tmp_val, sizeof (uint64_t));
                        buf = buf + sizeof (uint64_t);

                        (void) memcpy(buf, (char *)((biginteger_t *)
                            OBJ_PRI_DH942_PRIME(objp))->big_value,
                            ((biginteger_t *)
                            OBJ_PRI_DH942_PRIME(objp))->big_value_len);
                        buf = buf + ROUNDUP(((biginteger_t *)
                            OBJ_PRI_DH942_PRIME(objp))->big_value_len, 8);

                        /* base_len + base */
                        tmp_val = SWAP64((uint64_t)((biginteger_t *)
                            OBJ_PRI_DH942_BASE(objp))->big_value_len);
                        (void) memcpy(buf, (char *)&tmp_val, sizeof (uint64_t));
                        buf = buf + sizeof (uint64_t);

                        (void) memcpy(buf, (char *)((biginteger_t *)
                            OBJ_PRI_DH942_BASE(objp))->big_value,
                            ((biginteger_t *)
                            OBJ_PRI_DH942_BASE(objp))->big_value_len);
                        buf = buf + ROUNDUP(((biginteger_t *)
                            OBJ_PRI_DH942_BASE(objp))->big_value_len, 8);

                        /* subprime_len + subprime */
                        tmp_val = SWAP64((uint64_t)((biginteger_t *)
                            OBJ_PRI_DH942_SUBPRIME(objp))->big_value_len);
                        (void) memcpy(buf, (char *)&tmp_val, sizeof (uint64_t));
                        buf = buf + sizeof (uint64_t);

                        (void) memcpy(buf, (char *)((biginteger_t *)
                            OBJ_PRI_DH942_SUBPRIME(objp))->big_value,
                            ((biginteger_t *)
                            OBJ_PRI_DH942_SUBPRIME(objp))->big_value_len);
                        buf = buf + ROUNDUP(((biginteger_t *)
                            OBJ_PRI_DH942_SUBPRIME(objp))->big_value_len, 8);

                        /* value_len + value */
                        tmp_val = SWAP64((uint64_t)((biginteger_t *)
                            OBJ_PRI_DH942_VALUE(objp))->big_value_len);
                        (void) memcpy(buf, (char *)&tmp_val, sizeof (uint64_t));
                        buf = buf + sizeof (uint64_t);

                        (void) memcpy(buf, (char *)((biginteger_t *)
                            OBJ_PRI_DH942_VALUE(objp))->big_value,
                            ((biginteger_t *)
                            OBJ_PRI_DH942_VALUE(objp))->big_value_len);

                        break;

                } /* keytype */

                break;

        case CKO_SECRET_KEY:
                /* value_len  + value */
                tmp_val = SWAP64((uint64_t)OBJ_SEC_VALUE_LEN(objp));
                (void) memcpy(buf, (char *)&tmp_val, sizeof (uint64_t));
                buf = buf + sizeof (uint64_t);

                if (OBJ_SEC_VALUE_LEN(objp) > 0) {
                        (void) memcpy(buf, (char *)OBJ_SEC_VALUE(objp),
                            OBJ_SEC_VALUE_LEN(objp));
                        buf = buf + ROUNDUP(OBJ_SEC_VALUE_LEN(objp), 8);
                }

                break;

        case CKO_CERTIFICATE:

                switch (certtype) {
                case CKC_X_509:
                        /* subject_len + subject */
                        tmp_val = SWAP64((uint64_t)(((cert_attr_t *)
                            X509_CERT_SUBJECT(objp))->length));
                        (void) memcpy(buf, (char *)&tmp_val, sizeof (uint64_t));
                        buf = buf + sizeof (uint64_t);

                        (void) memcpy(buf, (char *)((cert_attr_t *)
                            X509_CERT_SUBJECT(objp))->value,
                            ((cert_attr_t *)
                            X509_CERT_SUBJECT(objp))->length);
                        buf = buf + ROUNDUP(((cert_attr_t *)
                            X509_CERT_SUBJECT(objp))->length, 8);

                        /* value_len + value */
                        tmp_val = SWAP64((uint64_t)(((cert_attr_t *)
                            X509_CERT_VALUE(objp))->length));
                        (void) memcpy(buf, (char *)&tmp_val, sizeof (uint64_t));
                        buf = buf + sizeof (uint64_t);

                        (void) memcpy(buf, (char *)((cert_attr_t *)
                            X509_CERT_VALUE(objp))->value,
                            ((cert_attr_t *)
                            X509_CERT_VALUE(objp))->length);
                        break;

                case CKC_X_509_ATTR_CERT:
                        /* owner_len + owner */
                        tmp_val = SWAP64((uint64_t)(((cert_attr_t *)
                            X509_ATTR_CERT_OWNER(objp))->length));
                        (void) memcpy(buf, (char *)&tmp_val, sizeof (uint64_t));
                        buf = buf + sizeof (uint64_t);

                        (void) memcpy(buf, (char *)((cert_attr_t *)
                            X509_ATTR_CERT_OWNER(objp))->value,
                            ((cert_attr_t *)
                            X509_ATTR_CERT_OWNER(objp))->length);
                        buf = buf + ROUNDUP(((cert_attr_t *)
                            X509_ATTR_CERT_OWNER(objp))->length, 8);

                        /* value_len + value */
                        tmp_val = SWAP64((uint64_t)(((cert_attr_t *)
                            X509_ATTR_CERT_VALUE(objp))->length));
                        (void) memcpy(buf, (char *)&tmp_val, sizeof (uint64_t));
                        buf = buf + sizeof (uint64_t);

                        (void) memcpy(buf, (char *)((cert_attr_t *)
                            X509_ATTR_CERT_VALUE(objp))->value,
                            ((cert_attr_t *)
                            X509_ATTR_CERT_VALUE(objp))->length);
                        break;
                }
                break;

        case CKO_DOMAIN_PARAMETERS:

                return (0);
        }
        return (CKR_OK);
}

/*
 * Unpack the object key in keystore format (the third part)
 * into soft_object_t.
 */
CK_RV
soft_unpack_object(soft_object_t *objp, uchar_t *buf)
{

        public_key_obj_t  *pbk;
        private_key_obj_t *pvk;
        secret_key_obj_t  *sck;
        certificate_obj_t *cert;
        CK_OBJECT_CLASS class = objp->class;
        CK_KEY_TYPE     keytype = objp->key_type;
        CK_CERTIFICATE_TYPE certtype = objp->cert_type;

        biginteger_t    modulus;
        biginteger_t    pubexpo;
        biginteger_t    prime;
        biginteger_t    subprime;
        biginteger_t    base;
        biginteger_t    value;

        biginteger_t    priexpo;
        biginteger_t    prime1;
        biginteger_t    prime2;
        biginteger_t    expo1;
        biginteger_t    expo2;
        biginteger_t    coef;
        CK_RV           rv = CKR_OK;
        ulong_t offset = 0;
        uint64_t tmp_val;

        /* prevent bigint_attr_cleanup from freeing invalid attr value */
        (void) memset(&modulus, 0x0, sizeof (biginteger_t));
        (void) memset(&pubexpo, 0x0, sizeof (biginteger_t));
        (void) memset(&prime, 0x0, sizeof (biginteger_t));
        (void) memset(&subprime, 0x0, sizeof (biginteger_t));
        (void) memset(&base, 0x0, sizeof (biginteger_t));
        (void) memset(&value, 0x0, sizeof (biginteger_t));

        (void) memset(&priexpo, 0x0, sizeof (biginteger_t));
        (void) memset(&prime1, 0x0, sizeof (biginteger_t));
        (void) memset(&prime2, 0x0, sizeof (biginteger_t));
        (void) memset(&expo1, 0x0, sizeof (biginteger_t));
        (void) memset(&expo2, 0x0, sizeof (biginteger_t));
        (void) memset(&coef, 0x0, sizeof (biginteger_t));

        switch (class) {

        case CKO_PUBLIC_KEY:
                /* Allocate storage for Public Key Object. */
                pbk = calloc(1, sizeof (public_key_obj_t));
                if (pbk == NULL) {
                        rv =  CKR_HOST_MEMORY;
                        return (rv);
                }

                objp->object_class_u.public_key = pbk;

                switch (keytype) {
                case CKK_RSA:                   /* modulus_bits */
                        (void) memcpy(&tmp_val, buf, sizeof (uint64_t));
                        KEY_PUB_RSA_MOD_BITS(pbk) = (CK_ULONG)(SWAP64(tmp_val));
                        buf = buf + sizeof (uint64_t);

                        /* modulus */
                        if ((rv = soft_unpack_obj_attribute(buf, &modulus,
                            NULL, &offset, B_FALSE)) != CKR_OK)
                                goto pub_cleanup;

                        copy_bigint_attr(&modulus, KEY_PUB_RSA_MOD(pbk));

                        buf += ROUNDUP(offset, 8);

                        /* pubexpo */
                        if ((rv = soft_unpack_obj_attribute(buf, &pubexpo,
                            NULL, &offset, B_FALSE)) != CKR_OK)
                                goto pub_cleanup;

                        copy_bigint_attr(&pubexpo, KEY_PUB_RSA_PUBEXPO(pbk));

                        break;

                case CKK_DSA:
                        /* prime */
                        if ((rv = soft_unpack_obj_attribute(buf, &prime,
                            NULL, &offset, B_FALSE)) != CKR_OK)
                                goto pub_cleanup;

                        copy_bigint_attr(&prime, KEY_PUB_DSA_PRIME(pbk));

                        buf += ROUNDUP(offset, 8);

                        /* subprime */
                        if ((rv = soft_unpack_obj_attribute(buf, &subprime,
                            NULL, &offset, B_FALSE)) != CKR_OK)
                                goto pub_cleanup;

                        copy_bigint_attr(&subprime, KEY_PUB_DSA_SUBPRIME(pbk));

                        buf += ROUNDUP(offset, 8);

                        /* base */
                        if ((rv = soft_unpack_obj_attribute(buf, &base,
                            NULL, &offset, B_FALSE)) != CKR_OK)
                                goto pub_cleanup;

                        copy_bigint_attr(&base, KEY_PUB_DSA_BASE(pbk));

                        buf += ROUNDUP(offset, 8);

                        /* value */
                        if ((rv = soft_unpack_obj_attribute(buf, &value,
                            NULL, &offset, B_FALSE)) != CKR_OK)
                                goto pub_cleanup;

                        copy_bigint_attr(&value, KEY_PUB_DSA_VALUE(pbk));

                        break;

                case CKK_DH:
                        /* prime */
                        if ((rv = soft_unpack_obj_attribute(buf, &prime,
                            NULL, &offset, B_FALSE)) != CKR_OK)
                                goto pub_cleanup;

                        copy_bigint_attr(&prime, KEY_PUB_DH_PRIME(pbk));

                        buf += ROUNDUP(offset, 8);

                        /* base */
                        if ((rv = soft_unpack_obj_attribute(buf, &base,
                            NULL, &offset, B_FALSE)) != CKR_OK)
                                goto pub_cleanup;

                        copy_bigint_attr(&base, KEY_PUB_DH_BASE(pbk));

                        buf += ROUNDUP(offset, 8);

                        /* value */
                        if ((rv = soft_unpack_obj_attribute(buf, &value,
                            NULL, &offset, B_FALSE)) != CKR_OK)
                                goto pub_cleanup;

                        copy_bigint_attr(&value, KEY_PUB_DH_VALUE(pbk));

                        break;

                case CKK_EC:
                        /* ec_point */
                        if ((rv = soft_unpack_obj_attribute(buf, &value,
                            NULL, &offset, B_FALSE)) != CKR_OK)
                                goto pri_cleanup;

                        copy_bigint_attr(&value, KEY_PUB_EC_POINT(pbk));
                        break;

                case CKK_X9_42_DH:
                        /* prime */
                        if ((rv = soft_unpack_obj_attribute(buf, &prime,
                            NULL, &offset, B_FALSE)) != CKR_OK)
                                goto pub_cleanup;

                        copy_bigint_attr(&prime, KEY_PUB_DH942_PRIME(pbk));

                        buf += ROUNDUP(offset, 8);

                        /* base */
                        if ((rv = soft_unpack_obj_attribute(buf, &base,
                            NULL, &offset, B_FALSE)) != CKR_OK)
                                goto pub_cleanup;

                        copy_bigint_attr(&base, KEY_PUB_DH942_BASE(pbk));

                        buf += ROUNDUP(offset, 8);

                        /* subprime */
                        if ((rv = soft_unpack_obj_attribute(buf, &subprime,
                            NULL, &offset, B_FALSE)) != CKR_OK)
                                goto pub_cleanup;

                        copy_bigint_attr(&subprime,
                            KEY_PUB_DH942_SUBPRIME(pbk));

                        buf += ROUNDUP(offset, 8);

                        /* value */
                        if ((rv = soft_unpack_obj_attribute(buf, &value,
                            NULL, &offset, B_FALSE)) != CKR_OK)
                                goto pub_cleanup;

                        copy_bigint_attr(&value, KEY_PUB_DH942_VALUE(pbk));

                        break;
                } /* keytype */

                break;

        case CKO_PRIVATE_KEY:
                /* Allocate storage for Private Key Object. */
                pvk = calloc(1, sizeof (private_key_obj_t));
                if (pvk == NULL) {
                        rv = CKR_HOST_MEMORY;
                        return (rv);
                }

                objp->object_class_u.private_key = pvk;

                switch (keytype) {
                case CKK_RSA:
                        /* modulus */
                        if ((rv = soft_unpack_obj_attribute(buf, &modulus,
                            NULL, &offset, B_FALSE)) != CKR_OK)
                                goto pri_cleanup;

                        copy_bigint_attr(&modulus, KEY_PRI_RSA_MOD(pvk));

                        buf += ROUNDUP(offset, 8);

                        /* pubexpo */
                        if ((rv = soft_unpack_obj_attribute(buf, &pubexpo,
                            NULL, &offset, B_FALSE)) != CKR_OK)
                                goto pri_cleanup;

                        copy_bigint_attr(&pubexpo, KEY_PRI_RSA_PUBEXPO(pvk));

                        buf += ROUNDUP(offset, 8);

                        /* priexpo */
                        if ((rv = soft_unpack_obj_attribute(buf, &priexpo,
                            NULL, &offset, B_FALSE)) != CKR_OK)
                                goto pri_cleanup;

                        copy_bigint_attr(&priexpo, KEY_PRI_RSA_PRIEXPO(pvk));

                        buf += ROUNDUP(offset, 8);

                        /* prime1 */
                        if ((rv = soft_unpack_obj_attribute(buf, &prime1,
                            NULL, &offset, B_FALSE)) != CKR_OK)
                                goto pri_cleanup;

                        copy_bigint_attr(&prime1, KEY_PRI_RSA_PRIME1(pvk));

                        buf += ROUNDUP(offset, 8);

                        /* prime2 */
                        if ((rv = soft_unpack_obj_attribute(buf, &prime2,
                            NULL, &offset, B_FALSE)) != CKR_OK)
                                goto pri_cleanup;

                        copy_bigint_attr(&prime2, KEY_PRI_RSA_PRIME2(pvk));

                        buf += ROUNDUP(offset, 8);

                        /* expo1 */
                        if ((rv = soft_unpack_obj_attribute(buf, &expo1,
                            NULL, &offset, B_FALSE)) != CKR_OK)
                                goto pri_cleanup;

                        copy_bigint_attr(&expo1, KEY_PRI_RSA_EXPO1(pvk));

                        buf += ROUNDUP(offset, 8);

                        /* expo2 */
                        if ((rv = soft_unpack_obj_attribute(buf, &expo2,
                            NULL, &offset, B_FALSE)) != CKR_OK)
                                goto pri_cleanup;

                        copy_bigint_attr(&expo2, KEY_PRI_RSA_EXPO2(pvk));

                        buf += ROUNDUP(offset, 8);

                        /* coef */
                        if ((rv = soft_unpack_obj_attribute(buf, &coef,
                            NULL, &offset, B_FALSE)) != CKR_OK)
                                goto pri_cleanup;

                        copy_bigint_attr(&coef, KEY_PRI_RSA_COEF(pvk));

                        break;

                case CKK_DSA:
                        /* prime */
                        if ((rv = soft_unpack_obj_attribute(buf, &prime,
                            NULL, &offset, B_FALSE)) != CKR_OK)
                                goto pri_cleanup;

                        copy_bigint_attr(&prime, KEY_PRI_DSA_PRIME(pvk));

                        buf += ROUNDUP(offset, 8);

                        /* subprime */
                        if ((rv = soft_unpack_obj_attribute(buf, &subprime,
                            NULL, &offset, B_FALSE)) != CKR_OK)
                                goto pri_cleanup;

                        copy_bigint_attr(&subprime, KEY_PRI_DSA_SUBPRIME(pvk));

                        buf += ROUNDUP(offset, 8);

                        /* base */
                        if ((rv = soft_unpack_obj_attribute(buf, &base,
                            NULL, &offset, B_FALSE)) != CKR_OK)
                                goto pri_cleanup;

                        copy_bigint_attr(&base, KEY_PRI_DSA_BASE(pvk));

                        buf += ROUNDUP(offset, 8);

                        /* value */
                        if ((rv = soft_unpack_obj_attribute(buf, &value,
                            NULL, &offset, B_FALSE)) != CKR_OK)
                                goto pri_cleanup;

                        copy_bigint_attr(&value, KEY_PRI_DSA_VALUE(pvk));

                        break;

                case CKK_DH:
                        /* value_bits */
                        (void) memcpy(&tmp_val, buf, sizeof (uint64_t));
                        KEY_PRI_DH_VAL_BITS(pvk) = (CK_ULONG)(SWAP64(tmp_val));
                        buf = buf + sizeof (uint64_t);

                        /* prime */
                        if ((rv = soft_unpack_obj_attribute(buf, &prime,
                            NULL, &offset, B_FALSE)) != CKR_OK)
                                goto pri_cleanup;

                        copy_bigint_attr(&prime, KEY_PRI_DH_PRIME(pvk));

                        buf += ROUNDUP(offset, 8);

                        /* base */
                        if ((rv = soft_unpack_obj_attribute(buf, &base,
                            NULL, &offset, B_FALSE)) != CKR_OK)
                                goto pri_cleanup;

                        copy_bigint_attr(&base, KEY_PRI_DH_BASE(pvk));

                        buf += ROUNDUP(offset, 8);

                        /* value */
                        if ((rv = soft_unpack_obj_attribute(buf, &value,
                            NULL, &offset, B_FALSE)) != CKR_OK)
                                goto pri_cleanup;

                        copy_bigint_attr(&value, KEY_PRI_DH_VALUE(pvk));

                        break;

                case CKK_EC:
                        /* value */
                        if ((rv = soft_unpack_obj_attribute(buf, &value,
                            NULL, &offset, B_FALSE)) != CKR_OK)
                                goto pri_cleanup;

                        copy_bigint_attr(&value, KEY_PRI_EC_VALUE(pvk));
                        break;

                case CKK_X9_42_DH:
                        /* prime */
                        if ((rv = soft_unpack_obj_attribute(buf, &prime,
                            NULL, &offset, B_FALSE)) != CKR_OK)
                                goto pri_cleanup;

                        copy_bigint_attr(&prime, KEY_PRI_DH942_PRIME(pvk));

                        buf += ROUNDUP(offset, 8);

                        /* base */
                        if ((rv = soft_unpack_obj_attribute(buf, &base,
                            NULL, &offset, B_FALSE)) != CKR_OK)
                                goto pri_cleanup;

                        copy_bigint_attr(&base, KEY_PRI_DH942_BASE(pvk));

                        buf += ROUNDUP(offset, 8);

                        /* subprime */
                        if ((rv = soft_unpack_obj_attribute(buf, &subprime,
                            NULL, &offset, B_FALSE)) != CKR_OK)
                                goto pri_cleanup;

                        copy_bigint_attr(&subprime, KEY_PRI_DH942_BASE(pvk));

                        buf += ROUNDUP(offset, 8);

                        /* value */
                        if ((rv = soft_unpack_obj_attribute(buf, &value,
                            NULL, &offset, B_FALSE)) != CKR_OK)
                                goto pri_cleanup;

                        copy_bigint_attr(&value, KEY_PRI_DH942_VALUE(pvk));

                        break;
                } /* keytype */

                break;

        case CKO_SECRET_KEY:
                /* Allocate storage for Secret Key Object. */
                sck = calloc(1, sizeof (secret_key_obj_t));
                if (sck == NULL) {
                        return (CKR_HOST_MEMORY);
                }

                objp->object_class_u.secret_key = sck;

                /* value */
                (void) memcpy((void *)&tmp_val, buf, sizeof (uint64_t));
                OBJ_SEC_VALUE_LEN(objp) = (CK_ULONG)(SWAP64(tmp_val));
                buf = buf + sizeof (uint64_t);

                if (OBJ_SEC_VALUE_LEN(objp) > 0) {
                        OBJ_SEC_VALUE(objp) = malloc(OBJ_SEC_VALUE_LEN(objp));
                        if (OBJ_SEC_VALUE(objp) == NULL) {
                                free(sck);
                                return (CKR_HOST_MEMORY);
                        }
                        (void) memcpy(OBJ_SEC_VALUE(objp), buf,
                            OBJ_SEC_VALUE_LEN(objp));

                        buf = buf + ROUNDUP(OBJ_SEC_VALUE_LEN(objp), 8);
                }

                return (rv);

        case CKO_CERTIFICATE:
                /* Allocate storage for Certificate Object. */
                cert = calloc(1, sizeof (certificate_obj_t));
                if (cert == NULL) {
                        return (CKR_HOST_MEMORY);
                }
                (void) memset((void *)cert, 0, sizeof (certificate_obj_t));

                cert->certificate_type = certtype;
                objp->object_class_u.certificate = cert;

                switch (certtype) {
                case CKC_X_509:
                        /* subject */
                        if ((rv = soft_unpack_obj_attribute(buf, NULL,
                            &cert->cert_type_u.x509.subject,
                            &offset, B_TRUE)) != CKR_OK) {
                                free(cert);
                                return (rv);
                        }

                        buf += ROUNDUP(offset, 8);

                        /* value */
                        if ((rv = soft_unpack_obj_attribute(buf, NULL,
                            &cert->cert_type_u.x509.value,
                            &offset, B_TRUE)) != CKR_OK) {
                                free(cert);
                                return (rv);
                        }

                        break;

                case CKC_X_509_ATTR_CERT:
                        /* owner */
                        if ((rv = soft_unpack_obj_attribute(buf, NULL,
                            &cert->cert_type_u.x509_attr.owner,
                            &offset, B_TRUE)) != CKR_OK) {
                                free(cert);
                                return (rv);
                        }

                        buf += ROUNDUP(offset, 8);

                        /* value */
                        if ((rv = soft_unpack_obj_attribute(buf, NULL,
                            &cert->cert_type_u.x509_attr.value,
                            &offset, B_TRUE)) != CKR_OK) {
                                free(cert);
                                return (rv);
                        }

                        break;
                }

                return (rv);

        case CKO_DOMAIN_PARAMETERS:

                break;
        }

pub_cleanup:
        /*
         * cleanup the storage allocated to the local variables.
         */
        if (rv != CKR_OK)
                free(pbk);
        bigint_attr_cleanup(&modulus);
        bigint_attr_cleanup(&pubexpo);
        bigint_attr_cleanup(&prime);
        bigint_attr_cleanup(&subprime);
        bigint_attr_cleanup(&base);
        bigint_attr_cleanup(&value);
        return (rv);

pri_cleanup:
        /*
         * cleanup the storage allocated to the local variables.
         */
        if (rv != CKR_OK)
                free(pvk);
        bigint_attr_cleanup(&modulus);
        bigint_attr_cleanup(&priexpo);
        bigint_attr_cleanup(&prime);
        bigint_attr_cleanup(&subprime);
        bigint_attr_cleanup(&base);
        bigint_attr_cleanup(&value);
        bigint_attr_cleanup(&pubexpo);
        bigint_attr_cleanup(&prime1);
        bigint_attr_cleanup(&prime2);
        bigint_attr_cleanup(&expo1);
        bigint_attr_cleanup(&expo2);
        bigint_attr_cleanup(&coef);
        return (rv);
}


/*
 * Store the token object to a keystore file.
 */
CK_RV
soft_put_object_to_keystore(soft_object_t *objp)
{

        uchar_t *buf;
        size_t len;
        CK_RV rv;

        rv = soft_keystore_pack_obj(objp, &buf, &len);
        if (rv != CKR_OK)
                return (rv);

        (void) pthread_mutex_lock(&soft_slot.slot_mutex);
        if (soft_keystore_put_new_obj(buf, len,
            !!(objp->object_type == TOKEN_PUBLIC), B_FALSE,
            &objp->ks_handle) == -1) {
                rv = CKR_FUNCTION_FAILED;
        }
        (void) pthread_mutex_unlock(&soft_slot.slot_mutex);

        freezero(buf, len);
        return (rv);
}

/*
 * Modify the in-core token object and then write it to
 * a keystore file.
 */
CK_RV
soft_modify_object_to_keystore(soft_object_t *objp)
{

        uchar_t *buf;
        size_t len;
        CK_RV rv;

        rv = soft_keystore_pack_obj(objp, &buf, &len);
        if (rv != CKR_OK)
                return (rv);

        /* B_TRUE: caller has held a writelock on the keystore */
        if (soft_keystore_modify_obj(&objp->ks_handle, buf, len,
            B_TRUE) < 0) {
                rv = CKR_FUNCTION_FAILED;
        }

        freezero(buf, len);
        return (rv);

}

/*
 * Read the token object from the keystore file.
 */
CK_RV
soft_get_token_objects_from_keystore(ks_search_type_t type)
{
        CK_RV rv;
        ks_obj_t        *ks_obj = NULL, *ks_obj_next;
        soft_object_t *new_objp = NULL;

        /* Load the token object from keystore based on the object type */
        rv = soft_keystore_get_objs(type, &ks_obj, B_FALSE);
        if (rv != CKR_OK) {
                return (rv);
        }

        while (ks_obj) {

                new_objp = calloc(1, sizeof (soft_object_t));
                if (new_objp == NULL) {
                        rv = CKR_HOST_MEMORY;
                        goto cleanup;
                }
                /* Convert the keystore format to memory format */
                rv = soft_keystore_unpack_obj(new_objp, ks_obj);
                if (rv != CKR_OK) {
                        if (new_objp->class == CKO_CERTIFICATE)
                                soft_cleanup_cert_object(new_objp);
                        else
                                soft_cleanup_object(new_objp);
                        goto cleanup;
                }

                soft_add_token_object_to_slot(new_objp);

                /* Free the ks_obj list */
                ks_obj_next = ks_obj->next;
                freezero(ks_obj->buf, ks_obj->size);
                free(ks_obj);
                ks_obj = ks_obj_next;
        }

        return (CKR_OK);

cleanup:
        while (ks_obj) {
                ks_obj_next = ks_obj->next;
                freezero(ks_obj->buf, ks_obj->size);
                free(ks_obj);
                ks_obj = ks_obj_next;
        }
        return (rv);
}

/*
 * soft_gen_crypt_key()
 *
 * Arguments:
 *
 *      pPIN:   pointer to caller provided Pin
 *      key:    output argument which contains the address of the
 *              pointer to encryption key in the soft_object_t.
 *              It is caller's responsibility to call soft_delete_object()
 *              if this key is no longer in use.
 *      saltdata: input argument (if non-NULL), or
 *                output argument (if NULL):
 *                address of pointer to the "salt" of the encryption key
 *
 * Description:
 *
 *      Generate an encryption key of the input PIN.
 *
 * Returns:
 *
 *      CKR_OK: no error
 *      Other: some error occurred while generating the encryption key
 *
 */
CK_RV
soft_gen_crypt_key(uchar_t *pPIN, soft_object_t **key, CK_BYTE **saltdata)
{
        CK_OBJECT_CLASS class = CKO_SECRET_KEY;
        CK_ATTRIBUTE tmpl[5];
        int attrs = 0;
        CK_RV rv;
        CK_MECHANISM Mechanism;
        CK_PKCS5_PBKD2_PARAMS params;
        CK_BYTE         salt[PBKD2_SALT_SIZE];
        CK_ULONG        keylen = AES_MIN_KEY_BYTES;
        CK_KEY_TYPE keytype = CKK_AES;
        static CK_BBOOL truevalue = TRUE;
        soft_object_t *secret_key;
        CK_ULONG        passwd_size;

        if (pPIN == NULL)
                return (CKR_FUNCTION_FAILED);

        tmpl[attrs].type = CKA_CLASS;
        tmpl[attrs].pValue = &class;
        tmpl[attrs].ulValueLen = sizeof (class);
        attrs++;

        tmpl[attrs].type = CKA_KEY_TYPE;
        tmpl[attrs].pValue = &keytype;
        tmpl[attrs].ulValueLen = sizeof (keytype);
        attrs++;

        tmpl[attrs].type = CKA_ENCRYPT;
        tmpl[attrs].pValue = &truevalue;
        tmpl[attrs].ulValueLen = sizeof (CK_BBOOL);
        attrs++;

        tmpl[attrs].type = CKA_DECRYPT;
        tmpl[attrs].pValue = &truevalue;
        tmpl[attrs].ulValueLen = sizeof (CK_BBOOL);
        attrs++;

        tmpl[attrs].type = CKA_VALUE_LEN;
        tmpl[attrs].pValue = &keylen;
        tmpl[attrs].ulValueLen = sizeof (keylen);
        attrs++;

        if (*saltdata == NULL) {
                bzero(salt, sizeof (salt));
                (void) pkcs11_get_nzero_urandom(salt, sizeof (salt));
                *saltdata = malloc(PBKD2_SALT_SIZE);
                if (*saltdata == NULL)
                        return (CKR_HOST_MEMORY);
                (void) memcpy(*saltdata, salt, PBKD2_SALT_SIZE);
        } else {
                bzero(salt, sizeof (salt));
                (void) memcpy(salt, *saltdata, PBKD2_SALT_SIZE);
        }

        Mechanism.mechanism = CKM_PKCS5_PBKD2;
        Mechanism.pParameter = &params;
        Mechanism.ulParameterLen = sizeof (params);
        passwd_size = (CK_ULONG)strlen((const char *)pPIN);

        params.saltSource = CKZ_SALT_SPECIFIED;
        params.pSaltSourceData = (void *)salt;
        params.ulSaltSourceDataLen = sizeof (salt);
        params.iterations = PBKD2_ITERATIONS;
        params.prf = CKP_PKCS5_PBKD2_HMAC_SHA1;
        params.pPrfData = NULL;
        params.ulPrfDataLen = 0;
        params.pPassword = (CK_UTF8CHAR_PTR)pPIN;
        params.ulPasswordLen = &passwd_size;

        rv = soft_gen_keyobject(tmpl, attrs, &secret_key, &token_session,
            CKO_SECRET_KEY, CKK_AES, 0, SOFT_GEN_KEY, B_TRUE);

        if (rv != CKR_OK) {
                return (rv);
        }

        keylen = OBJ_SEC_VALUE_LEN(secret_key);
        if ((OBJ_SEC_VALUE(secret_key) = malloc(keylen)) == NULL) {
                soft_delete_object(&token_session, secret_key,
                    B_FALSE, B_FALSE);
                return (CKR_HOST_MEMORY);
        }

        rv = soft_generate_pkcs5_pbkdf2_key(&token_session, &Mechanism,
            secret_key);

        if (rv != CKR_OK)
                soft_delete_object(&token_session, secret_key,
                    B_FALSE, B_FALSE);
        else
                *key = secret_key;

        return (rv);

}

/*
 * soft_gen_hmac_key()
 *
 * Arguments:
 *
 *      pPIN:   pointer to caller provided Pin
 *      key:    output argument which contains the address of the
 *              pointer to hmac key in the soft_object_t.
 *              It is caller's responsibility to call soft_delete_object()
 *              if this key is no longer in use.
 *      saltdata: input argument (if non-NULL), or
 *                output argument (if NULL):
 *                address of pointer to the "salt" of the hmac key
 *
 * Description:
 *
 *      Generate a hmac key of the input PIN.
 *
 * Returns:
 *
 *      CKR_OK: no error
 *      Other: some error occurred while generating the hmac key
 *
 */
CK_RV
soft_gen_hmac_key(uchar_t *pPIN, soft_object_t **key, CK_BYTE **saltdata)
{
        CK_OBJECT_CLASS class = CKO_SECRET_KEY;
        CK_ATTRIBUTE tmpl[5];
        int attrs = 0;
        CK_RV rv;
        CK_MECHANISM Mechanism;
        CK_PKCS5_PBKD2_PARAMS params;
        CK_BYTE         salt[PBKD2_SALT_SIZE];
        CK_ULONG        keylen = 16;
        CK_KEY_TYPE keytype = CKK_GENERIC_SECRET;
        static CK_BBOOL truevalue = TRUE;
        soft_object_t *secret_key;
        CK_ULONG        passwd_size;

        if (pPIN == NULL)
                return (CKR_FUNCTION_FAILED);

        tmpl[attrs].type = CKA_CLASS;
        tmpl[attrs].pValue = &class;
        tmpl[attrs].ulValueLen = sizeof (class);
        attrs++;

        tmpl[attrs].type = CKA_KEY_TYPE;
        tmpl[attrs].pValue = &keytype;
        tmpl[attrs].ulValueLen = sizeof (keytype);
        attrs++;

        tmpl[attrs].type = CKA_SIGN;
        tmpl[attrs].pValue = &truevalue;
        tmpl[attrs].ulValueLen = sizeof (CK_BBOOL);
        attrs++;

        tmpl[attrs].type = CKA_VERIFY;
        tmpl[attrs].pValue = &truevalue;
        tmpl[attrs].ulValueLen = sizeof (CK_BBOOL);
        attrs++;

        tmpl[attrs].type = CKA_VALUE_LEN;
        tmpl[attrs].pValue = &keylen;
        tmpl[attrs].ulValueLen = sizeof (keylen);
        attrs++;

        if (*saltdata == NULL) {
                bzero(salt, sizeof (salt));
                (void) pkcs11_get_nzero_urandom(salt, sizeof (salt));
                *saltdata = malloc(PBKD2_SALT_SIZE);
                if (*saltdata == NULL)
                        return (CKR_HOST_MEMORY);
                (void) memcpy(*saltdata, salt, PBKD2_SALT_SIZE);
        } else {
                bzero(salt, sizeof (salt));
                (void) memcpy(salt, *saltdata, PBKD2_SALT_SIZE);
        }

        Mechanism.mechanism = CKM_PKCS5_PBKD2;
        Mechanism.pParameter = &params;
        Mechanism.ulParameterLen = sizeof (params);
        passwd_size = (CK_ULONG)strlen((const char *)pPIN);

        params.saltSource = CKZ_SALT_SPECIFIED;
        params.pSaltSourceData = (void *)salt;
        params.ulSaltSourceDataLen = sizeof (salt);
        params.iterations = PBKD2_ITERATIONS;
        params.prf = CKP_PKCS5_PBKD2_HMAC_SHA1;
        params.pPrfData = NULL;
        params.ulPrfDataLen = 0;
        params.pPassword = (CK_UTF8CHAR_PTR)pPIN;
        params.ulPasswordLen = &passwd_size;

        rv = soft_gen_keyobject(tmpl, attrs, &secret_key, &token_session,
            CKO_SECRET_KEY, CKK_GENERIC_SECRET, 0, SOFT_GEN_KEY, B_TRUE);

        if (rv != CKR_OK) {
                return (rv);
        }

        keylen = OBJ_SEC_VALUE_LEN(secret_key);
        if ((OBJ_SEC_VALUE(secret_key) = malloc(keylen)) == NULL) {
                soft_delete_object(&token_session, secret_key,
                    B_FALSE, B_FALSE);
                return (CKR_HOST_MEMORY);
        }

        rv = soft_generate_pkcs5_pbkdf2_key(&token_session, &Mechanism,
            secret_key);

        if (rv != CKR_OK)
                soft_delete_object(&token_session, secret_key,
                    B_FALSE, B_FALSE);
        else
                *key = secret_key;

        return (rv);

}

/*
 * The token session is just a psuedo session (a place holder)
 * to hold some information during encryption/decryption and
 * sign/verify operations when writing/reading the keystore
 * token object.
 */
CK_RV
soft_init_token_session(void)
{


        token_session.magic_marker = SOFTTOKEN_SESSION_MAGIC;
        token_session.pApplication = NULL_PTR;
        token_session.Notify = NULL;
        token_session.flags = CKF_SERIAL_SESSION;
        token_session.state = CKS_RO_PUBLIC_SESSION;
        token_session.object_list = NULL;
        token_session.ses_refcnt = 0;
        token_session.ses_close_sync = 0;
        token_session.next = NULL;
        token_session.prev = NULL;

        /* Initialize the lock for the token session */
        if (pthread_mutex_init(&token_session.session_mutex, NULL) != 0) {
                return (CKR_CANT_LOCK);
        }

        (void) pthread_cond_init(&token_session.ses_free_cond, NULL);

        return (CKR_OK);

}

void
soft_destroy_token_session(void)
{

        (void) pthread_cond_destroy(&token_session.ses_free_cond);
        (void) pthread_mutex_destroy(&token_session.session_mutex);

}

/*
 * Encrypt/Decrypt the private token object when dealing with the keystore.
 * This function only applies to the private token object.
 */
CK_RV
soft_keystore_crypt(soft_object_t *key_p, uchar_t *ivec, boolean_t encrypt,
    CK_BYTE_PTR in, CK_ULONG in_len, CK_BYTE_PTR out, CK_ULONG_PTR out_len)
{
        CK_MECHANISM    mech;
        CK_RV rv;
        CK_ULONG tmplen, tmplen1;

        /*
         * The caller will pass NULL for "out" (output buffer) to find out
         * the output buffer size that it need to allocate for the encrption
         * or decryption.
         */
        if (out == NULL) {
                mech.mechanism = CKM_AES_CBC_PAD;
                mech.pParameter = (void *)ivec;
                mech.ulParameterLen = AES_BLOCK_LEN;

                if (encrypt)
                        rv = soft_aes_crypt_init_common(&token_session, &mech,
                            key_p, B_TRUE);
                else
                        rv = soft_aes_crypt_init_common(&token_session, &mech,
                            key_p, B_FALSE);

                if (rv != CKR_OK)
                        return (rv);

                /*
                 * Since out == NULL, the soft_aes_xxcrypt_common() will
                 * simply return the output buffer length to the caller.
                 */
                if (encrypt) {
                        rv = soft_aes_encrypt(&token_session, in, in_len,
                            out, out_len);
                } else {
                        rv = soft_aes_decrypt(&token_session, in, in_len,
                            out, out_len);
                }

        } else {
                /*
                 * The caller has allocated the output buffer, so that we
                 * are doing the real encryption/decryption this time.
                 */
                tmplen = *out_len;
                if (encrypt) {
                        rv = soft_aes_encrypt_update(&token_session, in,
                            in_len, out, &tmplen);
                        if (rv == CKR_OK) {
                                tmplen1 = *out_len - tmplen;
                                rv = soft_encrypt_final(&token_session,
                                    out+tmplen, &tmplen1);
                                *out_len = tmplen + tmplen1;
                        }
                } else {
                        rv = soft_aes_decrypt_update(&token_session, in,
                            in_len, out, &tmplen);
                        if (rv == CKR_OK) {
                                tmplen1 = *out_len - tmplen;
                                rv = soft_decrypt_final(&token_session,
                                    out+tmplen, &tmplen1);
                                *out_len = tmplen + tmplen1;
                        }
                }
        }

        return (rv);

}

/*
 * Sign/Verify the private token object for checking its data integrity
 * when dealing with the keystore.
 * This function only applies to the private token object.
 */
CK_RV
soft_keystore_hmac(soft_object_t *key_p, boolean_t sign,
    CK_BYTE_PTR in, CK_ULONG in_len, CK_BYTE_PTR out, CK_ULONG_PTR out_len)
{
        CK_MECHANISM mech;
        CK_RV rv;

        mech.mechanism = CKM_MD5_HMAC;
        mech.pParameter = NULL_PTR;
        mech.ulParameterLen = 0;

        rv = soft_hmac_sign_verify_init_common(&token_session, &mech,
            key_p, sign);

        if (rv != CKR_OK)
                return (rv);

        if (sign) {
                rv = soft_sign(&token_session, in, in_len, out, out_len);
        } else {
                rv = soft_verify(&token_session, in, in_len, out, *out_len);
        }

        return (rv);
}