2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A
2N/A/*
2N/A * Copyright (c) 2004, 2012, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A#include <stdlib.h>
2N/A#include <string.h>
2N/A#include <strings.h>
2N/A#include <lber.h>
2N/A#include <security/cryptoki.h>
2N/A#include "softDSA.h"
2N/A#include "softDH.h"
2N/A#include "softRSA.h"
2N/A#include "softObject.h"
2N/A#include "softASN1.h"
2N/A
2N/A#define OID_TAG 0x06
2N/A
2N/Astatic uchar_t DH_OID[] = {
2N/A /* DH key agreement OID: 1 . 2 . 840 . 113549 . 1 . 3 . 1 */
2N/A 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x03, 0x01
2N/A};
2N/A
2N/Astatic uchar_t DH942_OID[] = {
2N/A /* DH X9.42 OID: 1 . 2 . 840 . 10046 . 1 */
2N/A 0x2A, 0x86, 0x48, 0xCE, 0x3E, 0x01
2N/A};
2N/A
2N/Astatic uchar_t DSA_OID[] = {
2N/A /* DSA algorithm OID: 1 . 2 . 840 . 10040 . 4 . 1 */
2N/A 0x2A, 0x86, 0x48, 0xCE, 0x38, 0x04, 0x01
2N/A};
2N/A
2N/A#define MAX_RSA_KEY MAX_RSA_KEYLENGTH_IN_BYTES /* bytes in RSA key */
2N/Astatic uchar_t RSA_OID[] = {
2N/A /* RSA algorithm OID: 1 . 2 . 840 . 113549 . 1 . 1 . 1 */
2N/A 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01
2N/A};
2N/A
2N/A
2N/A/*
2N/A * If the first bit of big integer is non-zero (i.e, first byte is
2N/A * 0x80 or greater), it may be interpreted as an ASN.1 negative number.
2N/A * Add one leading byte of zero-padding only in these cases to ensure
2N/A * it is treated as an unsigned integer.
2N/A */
2N/Astatic CK_RV
2N/Apad_bigint_attr(biginteger_t *src, biginteger_t *dst)
2N/A{
2N/A int padding;
2N/A
2N/A /* Src and dst must already by previously allocated. */
2N/A if (src == NULL || dst == NULL)
2N/A return (CKR_HOST_MEMORY);
2N/A
2N/A if (src->big_value_len == 0) {
2N/A dst->big_value = NULL;
2N/A dst->big_value_len = 0;
2N/A return (CKR_OK);
2N/A }
2N/A /*
2N/A * Realloc() may free() or shrink previous memory location, so
2N/A * clear out potentially sensitive data before that happens.
2N/A */
2N/A if (dst->big_value != NULL)
2N/A (void) memset(dst->big_value, 0x0, dst->big_value_len);
2N/A
2N/A padding = (src->big_value[0] < 0x80) ? 0 : 1;
2N/A dst->big_value_len = src->big_value_len + padding;
2N/A
2N/A dst->big_value = realloc(dst->big_value, dst->big_value_len);
2N/A if (dst->big_value == NULL)
2N/A return (CKR_HOST_MEMORY);
2N/A
2N/A /* Set zero-pad at first byte, then append actual big_value. */
2N/A dst->big_value[0] = 0x0;
2N/A (void) memcpy(&(dst->big_value[padding]), src->big_value,
2N/A src->big_value_len);
2N/A return (CKR_OK);
2N/A}
2N/A
2N/A/*
2N/A * Sometimes there is one bytes of zero-padding, if a big integer may
2N/A * be interpreted as an ASN.1 negative number (i.e, the first bit is
2N/A * non-zero, the first byte is 0x80 or greater). Remove first byte
2N/A * of zero-padding in those cases from the decoded octet strings.
2N/A */
2N/Astatic CK_RV
2N/Aunpad_bigint_attr(biginteger_t src, biginteger_t *dst)
2N/A{
2N/A int offset;
2N/A
2N/A if (dst == NULL)
2N/A return (CKR_HOST_MEMORY);
2N/A
2N/A if (src.big_value_len == 0) {
2N/A dst->big_value = NULL;
2N/A dst->big_value_len = 0;
2N/A return (CKR_OK);
2N/A }
2N/A
2N/A offset = (src.big_value[0] == 0x00) ? 1 : 0;
2N/A dst->big_value_len = src.big_value_len - offset;
2N/A
2N/A /*
2N/A * Must allocate memory here because subsequent calls to
2N/A * copy_bigint_attr() just redirect pointer; it doesn't
2N/A * really copy the bigint like the function name implies.
2N/A */
2N/A dst->big_value = malloc(dst->big_value_len);
2N/A if (dst->big_value == NULL)
2N/A return (CKR_HOST_MEMORY);
2N/A
2N/A (void) memcpy(dst->big_value, &(src.big_value[offset]),
2N/A dst->big_value_len);
2N/A return (CKR_OK);
2N/A}
2N/A
2N/A
2N/A/* Encode RSA private key in ASN.1 BER syntax. */
2N/Astatic CK_RV
2N/Arsa_pri_to_asn1(soft_object_t *objp, uchar_t *buf, ulong_t *buf_len)
2N/A{
2N/A CK_RV rv = CKR_OK;
2N/A BerElement *key_asn = NULLBER, *p8obj_asn = NULLBER;
2N/A BerValue *key_octs = NULL, *p8obj_octs = NULL;
2N/A int version = SOFT_ASN_VERSION;
2N/A biginteger_t tmp_pad = { NULL, 0 };
2N/A
2N/A /*
2N/A * The ASN.1 syntax for an RSA private key is:
2N/A *
2N/A * PKCS#8 \* PrivateKeyInfo *\
2N/A * ---------------------------------
2N/A * Sequence {
2N/A * version INTEGER;
2N/A * Sequence { \* PrivateKeyAlgorithm *\
2N/A * OID 0x06, \* RSA algorithm OID *\
2N/A * param(NULL)
2N/A * }
2N/A * RSAPrivateKey OCTETSTRING =
2N/A * PKCS#1 \* RSAPrivateKey *\
2N/A * ---------------------------
2N/A * Sequence {
2N/A * version INTEGER,
2N/A * modulus INTEGER,
2N/A * publicExponent INTEGER,
2N/A * privateExponent INTEGER,
2N/A * prime1 INTEGER,
2N/A * prime2 INTEGER,
2N/A * exponent1 INTEGER,
2N/A * exponent2 INTEGER,
2N/A * coefficient INTEGER
2N/A * }
2N/A * }
2N/A *
2N/A * The code below starts building the innermost octets
2N/A * RSAPrivateKey, and then builds the PrivateKeyInfo
2N/A * sequence around that octet string. The BER syntax
2N/A * used in this function is (others may be possible):
2N/A * { i { to n } { i to to to to to to to to } }
2N/A * where "i" is for integers with fixed size
2N/A * where "to" is for integers that vary in size (length + value)
2N/A * where "n" is for nulls
2N/A * where "{}" delimit sequences
2N/A */
2N/A
2N/A /* RSAPrivateKey ... */
2N/A if ((key_asn = ber_alloc()) == NULLBER)
2N/A return (CKR_HOST_MEMORY);
2N/A
2N/A /* ... begin-sequence { version, */
2N/A if (ber_printf(key_asn, "{i", version) == -1) {
2N/A rv = CKR_GENERAL_ERROR;
2N/A goto cleanup_rsapri2asn;
2N/A }
2N/A
2N/A /* ... modulus, */
2N/A if ((rv = pad_bigint_attr(OBJ_PRI_RSA_MOD(objp), &tmp_pad)) != CKR_OK)
2N/A goto cleanup_rsapri2asn;
2N/A if (ber_printf(key_asn, "to", LBER_INTEGER,
2N/A tmp_pad.big_value, tmp_pad.big_value_len) == -1) {
2N/A rv = CKR_GENERAL_ERROR;
2N/A goto cleanup_rsapri2asn;
2N/A }
2N/A
2N/A /* ... public exponent, */
2N/A if ((rv = pad_bigint_attr(OBJ_PRI_RSA_PUBEXPO(objp), &tmp_pad)) !=
2N/A CKR_OK)
2N/A goto cleanup_rsapri2asn;
2N/A
2N/A else if (ber_printf(key_asn, "to", LBER_INTEGER, tmp_pad.big_value,
2N/A tmp_pad.big_value_len) == -1) {
2N/A rv = CKR_GENERAL_ERROR;
2N/A goto cleanup_rsapri2asn;
2N/A }
2N/A
2N/A /* ... private exponent, */
2N/A if ((rv = pad_bigint_attr(OBJ_PRI_RSA_PRIEXPO(objp), &tmp_pad)) !=
2N/A CKR_OK)
2N/A goto cleanup_rsapri2asn;
2N/A if (ber_printf(key_asn, "to", LBER_INTEGER,
2N/A tmp_pad.big_value, tmp_pad.big_value_len) == -1) {
2N/A rv = CKR_GENERAL_ERROR;
2N/A goto cleanup_rsapri2asn;
2N/A }
2N/A
2N/A /* ... prime 1, */
2N/A if ((rv = pad_bigint_attr(OBJ_PRI_RSA_PRIME1(objp), &tmp_pad)) !=
2N/A CKR_OK)
2N/A goto cleanup_rsapri2asn;
2N/A else if (ber_printf(key_asn, "to", LBER_INTEGER,
2N/A tmp_pad.big_value, tmp_pad.big_value_len) == -1) {
2N/A rv = CKR_GENERAL_ERROR;
2N/A goto cleanup_rsapri2asn;
2N/A }
2N/A
2N/A /* ... prime 2, */
2N/A if ((rv = pad_bigint_attr(OBJ_PRI_RSA_PRIME2(objp), &tmp_pad)) !=
2N/A CKR_OK)
2N/A goto cleanup_rsapri2asn;
2N/A else if (ber_printf(key_asn, "to", LBER_INTEGER,
2N/A tmp_pad.big_value, tmp_pad.big_value_len) == -1) {
2N/A rv = CKR_GENERAL_ERROR;
2N/A goto cleanup_rsapri2asn;
2N/A }
2N/A
2N/A /* ... exponent 1, */
2N/A if ((rv = pad_bigint_attr(OBJ_PRI_RSA_EXPO1(objp), &tmp_pad)) != CKR_OK)
2N/A goto cleanup_rsapri2asn;
2N/A else if (ber_printf(key_asn, "to", LBER_INTEGER,
2N/A tmp_pad.big_value, tmp_pad.big_value_len) == -1) {
2N/A rv = CKR_GENERAL_ERROR;
2N/A goto cleanup_rsapri2asn;
2N/A }
2N/A
2N/A /* ... exponent 2, */
2N/A if ((rv = pad_bigint_attr(OBJ_PRI_RSA_EXPO2(objp), &tmp_pad)) != CKR_OK)
2N/A goto cleanup_rsapri2asn;
2N/A else if (ber_printf(key_asn, "to", LBER_INTEGER,
2N/A tmp_pad.big_value, tmp_pad.big_value_len) == -1) {
2N/A rv = CKR_GENERAL_ERROR;
2N/A goto cleanup_rsapri2asn;
2N/A }
2N/A
2N/A /* ... coefficient } end-sequence */
2N/A if ((rv = pad_bigint_attr(OBJ_PRI_RSA_COEF(objp), &tmp_pad)) != CKR_OK)
2N/A goto cleanup_rsapri2asn;
2N/A else if (ber_printf(key_asn, "to}", LBER_INTEGER,
2N/A tmp_pad.big_value, tmp_pad.big_value_len) == -1) {
2N/A rv = CKR_GENERAL_ERROR;
2N/A goto cleanup_rsapri2asn;
2N/A }
2N/A
2N/A /* Convert key ASN.1 to octet string. */
2N/A if (ber_flatten(key_asn, &key_octs) == -1) {
2N/A rv = CKR_GENERAL_ERROR;
2N/A goto cleanup_rsapri2asn;
2N/A }
2N/A
2N/A /* PKCS#8 PrivateKeyInfo ... */
2N/A if ((p8obj_asn = ber_alloc()) == NULLBER) {
2N/A rv = CKR_HOST_MEMORY;
2N/A goto cleanup_rsapri2asn;
2N/A }
2N/A
2N/A /*
2N/A * Embed key octet string into PKCS#8 object ASN.1:
2N/A * begin-sequence {
2N/A * version
2N/A * begin-sequence {
2N/A * OID,
2N/A * NULL
2N/A * } end-sequence
2N/A * RSAPrivateKey
2N/A * } end-sequence
2N/A */
2N/A if (ber_printf(p8obj_asn, "{i{ton}o}", version,
2N/A OID_TAG, RSA_OID, sizeof (RSA_OID), /* NULL parameter, */
2N/A key_octs->bv_val, key_octs->bv_len) == -1) {
2N/A rv = CKR_GENERAL_ERROR;
2N/A goto cleanup_rsapri2asn;
2N/A }
2N/A
2N/A /* Convert PKCS#8 object ASN.1 to octet string. */
2N/A if (ber_flatten(p8obj_asn, &p8obj_octs) == -1) {
2N/A rv = CKR_GENERAL_ERROR;
2N/A goto cleanup_rsapri2asn;
2N/A }
2N/A
2N/A /* Ship out the PKCS#8 object ASN.1 octet string, if possible. */
2N/A /*
2N/A * If the user passes in a null buf, then buf_len is set.
2N/A * If the user passes in a value with buf_len, then it can
2N/A * be checked to see if the accompanying buf is big enough.
2N/A * If it is, the octet string is copied into a pre-malloc'd
2N/A * buf; otherwise the user must resize buf and call again.
2N/A * In either case, buf_len is reset to the corrected size.
2N/A * See PKCS#11 section 11.2.
2N/A */
2N/A#ifdef _LP64
2N/A /* LINTED E_CAST_INT_TO_SMALL_INT */
2N/A if ((buf == NULL) || ((ber_len_t)(*buf_len) < p8obj_octs->bv_len)) {
2N/A#else
2N/A if ((buf == NULL) || ((ber_len_t)(*buf_len) < p8obj_octs->bv_len)) {
2N/A#endif
2N/A *buf_len = p8obj_octs->bv_len;
2N/A rv = (buf == NULL) ? CKR_OK : CKR_BUFFER_TOO_SMALL;
2N/A goto cleanup_rsapri2asn;
2N/A }
2N/A
2N/A *buf_len = p8obj_octs->bv_len;
2N/A (void) memcpy(buf, p8obj_octs->bv_val, *buf_len);
2N/A
2N/Acleanup_rsapri2asn:
2N/A
2N/A if (tmp_pad.big_value != NULL) {
2N/A (void) memset(tmp_pad.big_value, 0x0, tmp_pad.big_value_len);
2N/A free(tmp_pad.big_value);
2N/A }
2N/A
2N/A if (key_asn != NULLBER)
2N/A ber_free(key_asn, 1);
2N/A
2N/A if (key_octs != NULL)
2N/A ber_bvfree(key_octs);
2N/A
2N/A if (p8obj_asn != NULLBER)
2N/A ber_free(p8obj_asn, 1);
2N/A
2N/A if (p8obj_octs != NULL)
2N/A ber_bvfree(p8obj_octs);
2N/A
2N/A return (rv);
2N/A}
2N/A
2N/A/* Encode DSA private key in ASN.1 BER syntax. */
2N/Astatic CK_RV
2N/Adsa_pri_to_asn1(soft_object_t *objp, uchar_t *buf, ulong_t *buf_len)
2N/A{
2N/A CK_RV rv = CKR_OK;
2N/A BerElement *key_asn = NULLBER, *p8obj_asn = NULLBER;
2N/A BerValue *key_octs = NULL, *p8obj_octs = NULL;
2N/A int version = SOFT_ASN_VERSION;
2N/A biginteger_t tmp_pad = { NULL, 0 };
2N/A
2N/A /*
2N/A * The ASN.1 syntax for a DSA private key is:
2N/A *
2N/A * PKCS#8 \* PrivateKeyInfo *\
2N/A * ---------------------------------
2N/A * Sequence {
2N/A * version INTEGER;
2N/A * Sequence { \* PrivateKeyAlgorithm *\
2N/A * OID 0x06, \* DSA algorithm OID *\
2N/A * param(DSS-params) OCTETSTRING =
2N/A * PKCS#? \* DSSParameter *\
2N/A * ----------------------------------
2N/A * Sequence {
2N/A * prime INTEGER,
2N/A * subprime INTEGER,
2N/A * base INTEGER,
2N/A * }
2N/A * }
2N/A * DSAPrivateKey OCTETSTRING =
2N/A * PKCS#1 \* DSAPrivateKey *\
2N/A * ---------------------------
2N/A * value INTEGER
2N/A * }
2N/A *
2N/A * The code below starts building the innermost octets
2N/A * DSAPrivateKey, and then builds the PrivateKeyInfo
2N/A * sequence around that octet string. The BER syntax
2N/A * used in this function is (others may be possible):
2N/A * { i { to { to to to } } to }
2N/A * where "i" is for integers with fixed size
2N/A * where "to" is for integers that vary in size (length + value)
2N/A * where "{}" delimit sequences
2N/A */
2N/A
2N/A /* DSAPrivateKey ... */
2N/A if ((key_asn = ber_alloc()) == NULLBER)
2N/A return (CKR_HOST_MEMORY);
2N/A
2N/A /* ... value */
2N/A if ((rv = pad_bigint_attr(OBJ_PRI_DSA_VALUE(objp), &tmp_pad)) != CKR_OK)
2N/A goto cleanup_dsapri2asn;
2N/A if (ber_printf(key_asn, "to", LBER_INTEGER,
2N/A tmp_pad.big_value, tmp_pad.big_value_len) == -1) {
2N/A rv = CKR_GENERAL_ERROR;
2N/A goto cleanup_dsapri2asn;
2N/A }
2N/A
2N/A /* Convert key ASN.1 to octet string. */
2N/A if (ber_flatten(key_asn, &key_octs) == -1) {
2N/A rv = CKR_GENERAL_ERROR;
2N/A goto cleanup_dsapri2asn;
2N/A }
2N/A
2N/A /* PKCS#8 PrivateKeyInfo ... */
2N/A if ((p8obj_asn = ber_alloc()) == NULLBER) {
2N/A rv = CKR_HOST_MEMORY;
2N/A goto cleanup_dsapri2asn;
2N/A }
2N/A
2N/A /*
2N/A * Start off the PKCS#8 object ASN.1:
2N/A * begin-sequence {
2N/A * version
2N/A * begin-sequence {
2N/A * OID,
2N/A * ...
2N/A */
2N/A if (ber_printf(p8obj_asn, "{i{to", version,
2N/A OID_TAG, DSA_OID, sizeof (DSA_OID)) == -1) {
2N/A rv = CKR_GENERAL_ERROR;
2N/A goto cleanup_dsapri2asn;
2N/A }
2N/A
2N/A /*
2N/A * Add DSS parameters:
2N/A * ...
2N/A * begin-sequence {
2N/A * prime,
2N/A * ...
2N/A */
2N/A if ((rv = pad_bigint_attr(OBJ_PRI_DSA_PRIME(objp), &tmp_pad)) != CKR_OK)
2N/A goto cleanup_dsapri2asn;
2N/A if (ber_printf(p8obj_asn, "{to", LBER_INTEGER,
2N/A tmp_pad.big_value, tmp_pad.big_value_len) == -1) {
2N/A rv = CKR_GENERAL_ERROR;
2N/A goto cleanup_dsapri2asn;
2N/A }
2N/A
2N/A /*
2N/A * ...
2N/A * subprime,
2N/A * ...
2N/A */
2N/A if ((rv = pad_bigint_attr(OBJ_PRI_DSA_SUBPRIME(objp), &tmp_pad)) !=
2N/A CKR_OK)
2N/A goto cleanup_dsapri2asn;
2N/A if (ber_printf(p8obj_asn, "to", LBER_INTEGER,
2N/A tmp_pad.big_value, tmp_pad.big_value_len) == -1) {
2N/A rv = CKR_GENERAL_ERROR;
2N/A goto cleanup_dsapri2asn;
2N/A }
2N/A
2N/A /*
2N/A * ...
2N/A * base
2N/A * } end-sequence
2N/A */
2N/A if ((rv = pad_bigint_attr(OBJ_PRI_DSA_BASE(objp), &tmp_pad)) != CKR_OK)
2N/A goto cleanup_dsapri2asn;
2N/A if (ber_printf(p8obj_asn, "to}", LBER_INTEGER,
2N/A tmp_pad.big_value, tmp_pad.big_value_len) == -1) {
2N/A rv = CKR_GENERAL_ERROR;
2N/A goto cleanup_dsapri2asn;
2N/A }
2N/A
2N/A /*
2N/A * Add the key octet string:
2N/A * } end-sequence
2N/A * DSAPrivateKey
2N/A * } end-sequence
2N/A */
2N/A if (ber_printf(p8obj_asn, "}o}",
2N/A key_octs->bv_val, key_octs->bv_len) == -1) {
2N/A rv = CKR_GENERAL_ERROR;
2N/A goto cleanup_dsapri2asn;
2N/A }
2N/A
2N/A /* Convert PKCS#8 object ASN.1 to octet string. */
2N/A if (ber_flatten(p8obj_asn, &p8obj_octs) == -1) {
2N/A rv = CKR_GENERAL_ERROR;
2N/A goto cleanup_dsapri2asn;
2N/A }
2N/A
2N/A /* Ship out the PKCS#8 object ASN.1 octet string, if possible. */
2N/A /*
2N/A * If the user passes in a null buf, then buf_len is set.
2N/A * If the user passes in a value with buf_len, then it can
2N/A * be checked to see if the accompanying buf is big enough.
2N/A * If it is, the octet string is copied into a pre-malloc'd
2N/A * buf; otherwise the user must resize buf and call again.
2N/A * In either case, buf_len is reset to the corrected size.
2N/A * See PKCS#11 section 11.2.
2N/A */
2N/A#ifdef _LP64
2N/A /* LINTED E_CAST_INT_TO_SMALL_INT */
2N/A if ((buf == NULL) || ((ber_len_t)(*buf_len) < p8obj_octs->bv_len)) {
2N/A#else
2N/A if ((buf == NULL) || ((ber_len_t)(*buf_len) < p8obj_octs->bv_len)) {
2N/A#endif
2N/A *buf_len = p8obj_octs->bv_len;
2N/A rv = (buf == NULL) ? CKR_OK : CKR_BUFFER_TOO_SMALL;
2N/A goto cleanup_dsapri2asn;
2N/A }
2N/A
2N/A *buf_len = p8obj_octs->bv_len;
2N/A (void) memcpy(buf, p8obj_octs->bv_val, *buf_len);
2N/A
2N/Acleanup_dsapri2asn:
2N/A
2N/A if (tmp_pad.big_value != NULL) {
2N/A (void) memset(tmp_pad.big_value, 0x0, tmp_pad.big_value_len);
2N/A free(tmp_pad.big_value);
2N/A }
2N/A
2N/A if (key_asn != NULLBER)
2N/A ber_free(key_asn, 1);
2N/A
2N/A if (key_octs != NULL)
2N/A ber_bvfree(key_octs);
2N/A
2N/A if (p8obj_asn != NULLBER)
2N/A ber_free(p8obj_asn, 1);
2N/A
2N/A if (p8obj_octs != NULL)
2N/A ber_bvfree(p8obj_octs);
2N/A
2N/A return (rv);
2N/A}
2N/A
2N/A/* Encode DH private key in ASN.1 BER syntax. */
2N/Astatic CK_RV
2N/Adh_pri_to_asn1(soft_object_t *objp, uchar_t *buf, ulong_t *buf_len)
2N/A{
2N/A CK_RV rv = CKR_OK;
2N/A BerElement *key_asn = NULLBER, *p8obj_asn = NULLBER;
2N/A BerValue *key_octs = NULL, *p8obj_octs = NULL;
2N/A int version = SOFT_ASN_VERSION;
2N/A biginteger_t tmp_pad = { NULL, 0 };
2N/A
2N/A /*
2N/A * The ASN.1 syntax for a DH private key is:
2N/A *
2N/A * PKCS#8 \* PrivateKeyInfo *\
2N/A * ---------------------------------
2N/A * Sequence {
2N/A * version INTEGER;
2N/A * Sequence { \* PrivateKeyAlgorithm *\
2N/A * OID 0x06, \* DH algorithm OID *\
2N/A * param(DH-params) OCTETSTRING =
2N/A * PKCS#3 \* DHParameter *\
2N/A * -------------------------
2N/A * Sequence {
2N/A * prime INTEGER,
2N/A * base INTEGER
2N/A * }
2N/A * }
2N/A * DHPrivateKey OCTETSTRING =
2N/A * PKCS#1 \* DHPrivateKey *\
2N/A * --------------------------
2N/A * value INTEGER
2N/A * }
2N/A *
2N/A * The code below starts building the innermost octets
2N/A * DHPrivateKey, and then builds the PrivateKeyInfo
2N/A * sequence around that octet string. The BER syntax
2N/A * used in this function is (others may be possible):
2N/A * { i { to { to to } } to }
2N/A * where "i" is for integers with fixed size
2N/A * where "to" is for integers that vary in size (length + value)
2N/A * where "{}" delimit sequences
2N/A */
2N/A
2N/A /* DHPrivateKey ... */
2N/A if ((key_asn = ber_alloc()) == NULLBER)
2N/A return (CKR_HOST_MEMORY);
2N/A
2N/A /* ... value */
2N/A if ((rv = pad_bigint_attr(OBJ_PRI_DH_VALUE(objp), &tmp_pad)) != CKR_OK)
2N/A goto cleanup_dhpri2asn;
2N/A if (ber_printf(key_asn, "to", LBER_INTEGER,
2N/A tmp_pad.big_value, tmp_pad.big_value_len) == -1) {
2N/A rv = CKR_GENERAL_ERROR;
2N/A goto cleanup_dhpri2asn;
2N/A }
2N/A
2N/A /* Convert key ASN.1 to octet string. */
2N/A if (ber_flatten(key_asn, &key_octs) == -1) {
2N/A rv = CKR_GENERAL_ERROR;
2N/A goto cleanup_dhpri2asn;
2N/A }
2N/A
2N/A /* PKCS#8 PrivateKeyInfo ... */
2N/A if ((p8obj_asn = ber_alloc()) == NULLBER) {
2N/A rv = CKR_HOST_MEMORY;
2N/A goto cleanup_dhpri2asn;
2N/A }
2N/A
2N/A /*
2N/A * Start off the PKCS#8 object ASN.1:
2N/A * begin-sequence {
2N/A * version
2N/A * begin-sequence {
2N/A * OID,
2N/A * ...
2N/A */
2N/A if (ber_printf(p8obj_asn, "{i{to", version,
2N/A OID_TAG, DH_OID, sizeof (DH_OID)) == -1) {
2N/A rv = CKR_GENERAL_ERROR;
2N/A goto cleanup_dhpri2asn;
2N/A }
2N/A
2N/A /*
2N/A * Add DH parameters:
2N/A * ...
2N/A * begin-sequence {
2N/A * prime,
2N/A * ...
2N/A */
2N/A if ((rv = pad_bigint_attr(OBJ_PRI_DH_PRIME(objp), &tmp_pad)) != CKR_OK)
2N/A goto cleanup_dhpri2asn;
2N/A if (ber_printf(p8obj_asn, "{to", LBER_INTEGER,
2N/A tmp_pad.big_value, tmp_pad.big_value_len) == -1) {
2N/A rv = CKR_GENERAL_ERROR;
2N/A goto cleanup_dhpri2asn;
2N/A }
2N/A
2N/A /*
2N/A * ...
2N/A * base
2N/A * } end-sequence
2N/A */
2N/A if ((rv = pad_bigint_attr(OBJ_PRI_DH_BASE(objp), &tmp_pad)) != CKR_OK)
2N/A goto cleanup_dhpri2asn;
2N/A if (ber_printf(p8obj_asn, "to}", LBER_INTEGER,
2N/A tmp_pad.big_value, tmp_pad.big_value_len) == -1) {
2N/A rv = CKR_GENERAL_ERROR;
2N/A goto cleanup_dhpri2asn;
2N/A }
2N/A
2N/A /*
2N/A * Add the key octet string:
2N/A * } end-sequence
2N/A * DSAPrivateKey
2N/A * } end-sequence
2N/A */
2N/A if (ber_printf(p8obj_asn, "}o}",
2N/A key_octs->bv_val, key_octs->bv_len) == -1) {
2N/A rv = CKR_GENERAL_ERROR;
2N/A goto cleanup_dhpri2asn;
2N/A }
2N/A
2N/A /* Convert PKCS#8 object ASN.1 to octet string. */
2N/A if (ber_flatten(p8obj_asn, &p8obj_octs) == -1) {
2N/A rv = CKR_GENERAL_ERROR;
2N/A goto cleanup_dhpri2asn;
2N/A }
2N/A
2N/A /* Ship out the PKCS#8 object ASN.1 octet string, if possible. */
2N/A /*
2N/A * If the user passes in a null buf, then buf_len is set.
2N/A * If the user passes in a value with buf_len, then it can
2N/A * be checked to see if the accompanying buf is big enough.
2N/A * If it is, the octet string is copied into a pre-malloc'd
2N/A * buf; otherwise the user must resize buf and call again.
2N/A * In either case, buf_len is reset to the corrected size.
2N/A * See PKCS#11 section 11.2.
2N/A */
2N/A#ifdef _LP64
2N/A /* LINTED E_CAST_INT_TO_SMALL_INT */
2N/A if ((buf == NULL) || ((ber_len_t)(*buf_len) < p8obj_octs->bv_len)) {
2N/A#else
2N/A if ((buf == NULL) || ((ber_len_t)(*buf_len) < p8obj_octs->bv_len)) {
2N/A#endif
2N/A *buf_len = p8obj_octs->bv_len;
2N/A rv = (buf == NULL) ? CKR_OK : CKR_BUFFER_TOO_SMALL;
2N/A goto cleanup_dhpri2asn;
2N/A }
2N/A
2N/A *buf_len = p8obj_octs->bv_len;
2N/A (void) memcpy(buf, p8obj_octs->bv_val, *buf_len);
2N/A
2N/Acleanup_dhpri2asn:
2N/A
2N/A if (tmp_pad.big_value != NULL) {
2N/A (void) memset(tmp_pad.big_value, 0x0, tmp_pad.big_value_len);
2N/A free(tmp_pad.big_value);
2N/A }
2N/A
2N/A if (key_asn != NULLBER)
2N/A ber_free(key_asn, 1);
2N/A
2N/A if (key_octs != NULL)
2N/A ber_bvfree(key_octs);
2N/A
2N/A if (p8obj_asn != NULLBER)
2N/A ber_free(p8obj_asn, 1);
2N/A
2N/A if (p8obj_octs != NULL)
2N/A ber_bvfree(p8obj_octs);
2N/A
2N/A return (rv);
2N/A}
2N/A
2N/A/* Encode DH X9.42 private key in ASN.1 BER syntax. */
2N/Astatic CK_RV
2N/Ax942_dh_pri_to_asn1(soft_object_t *objp, uchar_t *buf, ulong_t *buf_len)
2N/A{
2N/A CK_RV rv = CKR_OK;
2N/A BerElement *key_asn = NULLBER, *p8obj_asn = NULLBER;
2N/A BerValue *key_octs = NULL, *p8obj_octs = NULL;
2N/A int version = SOFT_ASN_VERSION;
2N/A biginteger_t tmp_pad = { NULL, 0 };
2N/A
2N/A /*
2N/A * The ASN.1 syntax for a X9.42 DH private key is:
2N/A *
2N/A * PKCS#8 \* PrivateKeyInfo *\
2N/A * ---------------------------------
2N/A * Sequence {
2N/A * version INTEGER;
2N/A * Sequence { \* PrivateKeyAlgorithm *\
2N/A * OID 0x06, \* DH X9.42 algorithm OID *\
2N/A * param(DH-params) OCTETSTRING =
2N/A * PKCS#3 \* DHParameter *\
2N/A * -------------------------
2N/A * Sequence {
2N/A * prime INTEGER,
2N/A * base INTEGER,
2N/A * subprime INTEGER \* for X9.42 *\
2N/A * }
2N/A * }
2N/A * DHPrivateKey OCTETSTRING =
2N/A * PKCS#1 \* DHPrivateKey *\
2N/A * --------------------------
2N/A * value INTEGER
2N/A * }
2N/A *
2N/A * The code below starts building the innermost octets
2N/A * DHPrivateKey, and then builds the PrivateKeyInfo
2N/A * sequence around that octet string. The BER syntax
2N/A * used in this function is (others may be possible):
2N/A * { i { to { to to } } to }
2N/A * where "i" is for integers with fixed size
2N/A * where "to" is for integers that vary in size (length + value)
2N/A * where "{}" delimit sequences
2N/A */
2N/A
2N/A /* DHPrivateKey ... */
2N/A if ((key_asn = ber_alloc()) == NULLBER)
2N/A return (CKR_HOST_MEMORY);
2N/A
2N/A /* ... value */
2N/A if ((rv = pad_bigint_attr(OBJ_PRI_DH942_VALUE(objp), &tmp_pad)) !=
2N/A CKR_OK)
2N/A goto cleanup_x942dhpri2asn;
2N/A if (ber_printf(key_asn, "to", LBER_INTEGER,
2N/A tmp_pad.big_value, tmp_pad.big_value_len) == -1) {
2N/A rv = CKR_GENERAL_ERROR;
2N/A goto cleanup_x942dhpri2asn;
2N/A }
2N/A
2N/A /* Convert key ASN.1 to octet string. */
2N/A if (ber_flatten(key_asn, &key_octs) == -1) {
2N/A rv = CKR_GENERAL_ERROR;
2N/A goto cleanup_x942dhpri2asn;
2N/A }
2N/A
2N/A /* PKCS#8 PrivateKeyInfo ... */
2N/A if ((p8obj_asn = ber_alloc()) == NULLBER) {
2N/A rv = CKR_HOST_MEMORY;
2N/A goto cleanup_x942dhpri2asn;
2N/A }
2N/A
2N/A /*
2N/A * Start off the PKCS#8 object ASN.1:
2N/A * begin-sequence {
2N/A * version
2N/A * begin-sequence {
2N/A * OID,
2N/A * ...
2N/A */
2N/A if (ber_printf(p8obj_asn, "{i{to", version,
2N/A OID_TAG, DH942_OID, sizeof (DH942_OID)) == -1) {
2N/A rv = CKR_GENERAL_ERROR;
2N/A goto cleanup_x942dhpri2asn;
2N/A }
2N/A
2N/A /*
2N/A * Add DH parameters:
2N/A * ...
2N/A * begin-sequence {
2N/A * prime,
2N/A * ...
2N/A */
2N/A if ((rv = pad_bigint_attr(OBJ_PRI_DH942_PRIME(objp), &tmp_pad)) !=
2N/A CKR_OK)
2N/A goto cleanup_x942dhpri2asn;
2N/A if (ber_printf(p8obj_asn, "{to", LBER_INTEGER,
2N/A tmp_pad.big_value, tmp_pad.big_value_len) == -1) {
2N/A rv = CKR_GENERAL_ERROR;
2N/A goto cleanup_x942dhpri2asn;
2N/A }
2N/A
2N/A /*
2N/A * ...
2N/A * base,
2N/A * ...
2N/A */
2N/A if ((rv = pad_bigint_attr(OBJ_PRI_DH942_BASE(objp), &tmp_pad)) !=
2N/A CKR_OK)
2N/A goto cleanup_x942dhpri2asn;
2N/A if (ber_printf(p8obj_asn, "to", LBER_INTEGER,
2N/A tmp_pad.big_value, tmp_pad.big_value_len) == -1) {
2N/A rv = CKR_GENERAL_ERROR;
2N/A goto cleanup_x942dhpri2asn;
2N/A }
2N/A
2N/A /*
2N/A * ...
2N/A * subprime
2N/A * } end-sequence
2N/A */
2N/A if ((rv = pad_bigint_attr(OBJ_PRI_DH942_SUBPRIME(objp), &tmp_pad)) !=
2N/A CKR_OK)
2N/A goto cleanup_x942dhpri2asn;
2N/A if (ber_printf(p8obj_asn, "to}", LBER_INTEGER,
2N/A tmp_pad.big_value, tmp_pad.big_value_len) == -1) {
2N/A rv = CKR_GENERAL_ERROR;
2N/A goto cleanup_x942dhpri2asn;
2N/A }
2N/A
2N/A /*
2N/A * Add the key octet string:
2N/A * } end-sequence
2N/A * DHPrivateKey
2N/A * } end-sequence
2N/A */
2N/A if (ber_printf(p8obj_asn, "}o}",
2N/A key_octs->bv_val, key_octs->bv_len) == -1) {
2N/A rv = CKR_GENERAL_ERROR;
2N/A goto cleanup_x942dhpri2asn;
2N/A }
2N/A
2N/A /* Convert PKCS#8 object ASN.1 to octet string. */
2N/A if (ber_flatten(p8obj_asn, &p8obj_octs) == -1) {
2N/A rv = CKR_GENERAL_ERROR;
2N/A goto cleanup_x942dhpri2asn;
2N/A }
2N/A
2N/A /* Ship out the PKCS#8 object ASN.1 octet string, if possible. */
2N/A /*
2N/A * If the user passes in a null buf, then buf_len is set.
2N/A * If the user passes in a value with buf_len, then it can
2N/A * be checked to see if the accompanying buf is big enough.
2N/A * If it is, the octet string is copied into a pre-malloc'd
2N/A * buf; otherwise the user must resize buf and call again.
2N/A * In either case, buf_len is reset to the corrected size.
2N/A * See PKCS#11 section 11.2.
2N/A */
2N/A#ifdef _LP64
2N/A /* LINTED E_CAST_INT_TO_SMALL_INT */
2N/A if ((buf == NULL) || ((ber_len_t)(*buf_len) < p8obj_octs->bv_len)) {
2N/A#else
2N/A if ((buf == NULL) || ((ber_len_t)(*buf_len) < p8obj_octs->bv_len)) {
2N/A#endif
2N/A *buf_len = p8obj_octs->bv_len;
2N/A rv = (buf == NULL) ? CKR_OK : CKR_BUFFER_TOO_SMALL;
2N/A goto cleanup_x942dhpri2asn;
2N/A }
2N/A
2N/A *buf_len = p8obj_octs->bv_len;
2N/A (void) memcpy(buf, p8obj_octs->bv_val, *buf_len);
2N/A
2N/Acleanup_x942dhpri2asn:
2N/A
2N/A if (tmp_pad.big_value != NULL) {
2N/A (void) memset(tmp_pad.big_value, 0x0, tmp_pad.big_value_len);
2N/A free(tmp_pad.big_value);
2N/A }
2N/A
2N/A if (key_asn != NULLBER)
2N/A ber_free(key_asn, 1);
2N/A
2N/A if (key_octs != NULL)
2N/A ber_bvfree(key_octs);
2N/A
2N/A if (p8obj_asn != NULLBER)
2N/A ber_free(p8obj_asn, 1);
2N/A
2N/A if (p8obj_octs != NULL)
2N/A ber_bvfree(p8obj_octs);
2N/A
2N/A return (rv);
2N/A}
2N/A
2N/A/*
2N/A * Encode the object key from the soft_object_t into ASN.1 format.
2N/A */
2N/ACK_RV
2N/Asoft_object_to_asn1(soft_object_t *objp, uchar_t *buf, ulong_t *buf_len)
2N/A{
2N/A CK_OBJECT_CLASS class = objp->class;
2N/A CK_KEY_TYPE keytype = objp->key_type;
2N/A
2N/A switch (class) {
2N/A
2N/A case CKO_PRIVATE_KEY:
2N/A switch (keytype) {
2N/A case CKK_RSA:
2N/A return (rsa_pri_to_asn1(objp, buf, buf_len));
2N/A
2N/A case CKK_DSA:
2N/A return (dsa_pri_to_asn1(objp, buf, buf_len));
2N/A
2N/A case CKK_DH:
2N/A return (dh_pri_to_asn1(objp, buf, buf_len));
2N/A
2N/A case CKK_X9_42_DH:
2N/A return (x942_dh_pri_to_asn1(objp, buf, buf_len));
2N/A
2N/A default:
2N/A return (CKR_FUNCTION_NOT_SUPPORTED);
2N/A } /* keytype */
2N/A
2N/A /* NOTREACHED */
2N/A break;
2N/A
2N/A default:
2N/A return (CKR_FUNCTION_NOT_SUPPORTED);
2N/A
2N/A } /* class */
2N/A}
2N/A
2N/A/* Decode ASN.1 BER syntax into RSA private key. */
2N/Astatic CK_RV
2N/Aasn1_to_rsa_pri(private_key_obj_t *keyp, uchar_t *buf, ulong_t buf_len)
2N/A{
2N/A CK_RV rv = CKR_OK;
2N/A BerValue p8obj_octs, key_octs;
2N/A BerElement *p8obj_asn = NULLBER, *key_asn = NULLBER;
2N/A ber_len_t size, tmplen;
2N/A char *cookie;
2N/A int version;
2N/A uchar_t oid[sizeof (RSA_OID) + 1];
2N/A biginteger_t tmp, tmp_nopad = { NULL, 0 };
2N/A
2N/A p8obj_octs.bv_val = (char *)buf;
2N/A#ifdef _LP64
2N/A /* LINTED E_CAST_INT_TO_SMALL_INT */
2N/A p8obj_octs.bv_len = (ber_len_t)buf_len;
2N/A#else
2N/A p8obj_octs.bv_len = (ber_len_t)buf_len;
2N/A#endif
2N/A
2N/A key_octs.bv_val = NULL;
2N/A key_octs.bv_len = 0;
2N/A
2N/A /* Decode PKCS#8 object ASN.1, verifying it is RSA private key. */
2N/A if ((p8obj_asn = ber_init(&p8obj_octs)) == NULLBER)
2N/A return (CKR_GENERAL_ERROR);
2N/A
2N/A /* PKCS#8 PrivateKeyInfo ... */
2N/A if (ber_first_element(p8obj_asn, &size, &cookie) != LBER_INTEGER) {
2N/A rv = CKR_WRAPPED_KEY_INVALID;
2N/A goto cleanup_asn2rsapri;
2N/A }
2N/A /* ... begin-sequence { version, */
2N/A (void) ber_scanf(p8obj_asn, "i", &version); /* "{i" ? */
2N/A
2N/A if (ber_next_element(p8obj_asn, &size, cookie) != LBER_SEQUENCE) {
2N/A rv = CKR_WRAPPED_KEY_INVALID;
2N/A goto cleanup_asn2rsapri;
2N/A }
2N/A /* ... begin-sequence { */
2N/A (void) ber_scanf(p8obj_asn, "{");
2N/A
2N/A if (ber_next_element(p8obj_asn, &size, cookie) != OID_TAG) {
2N/A rv = CKR_WRAPPED_KEY_INVALID;
2N/A goto cleanup_asn2rsapri;
2N/A }
2N/A /* ... OID, \* RSA algorithm OID *\ */
2N/A if (size != sizeof (RSA_OID)) {
2N/A rv = CKR_FUNCTION_NOT_SUPPORTED;
2N/A goto cleanup_asn2rsapri;
2N/A }
2N/A size = sizeof (oid);
2N/A (void) ber_scanf(p8obj_asn, "s", oid, &size);
2N/A if (memcmp(oid, RSA_OID, size) != 0) {
2N/A rv = CKR_FUNCTION_NOT_SUPPORTED;
2N/A goto cleanup_asn2rsapri;
2N/A }
2N/A
2N/A if (ber_next_element(p8obj_asn, &size, cookie) != LBER_NULL) {
2N/A rv = CKR_WRAPPED_KEY_INVALID;
2N/A goto cleanup_asn2rsapri;
2N/A }
2N/A /* ... param(NULL) } end-sequence */
2N/A (void) ber_scanf(p8obj_asn, "n"); /* "n}" ? */
2N/A
2N/A if (ber_next_element(p8obj_asn, &size, cookie) != LBER_OCTETSTRING) {
2N/A rv = CKR_WRAPPED_KEY_INVALID;
2N/A goto cleanup_asn2rsapri;
2N/A }
2N/A /* ... RSAPrivateKey } end-sequence */
2N/A key_octs.bv_len = size + 1;
2N/A if ((key_octs.bv_val = malloc(size + 1)) == NULL) {
2N/A rv = CKR_HOST_MEMORY;
2N/A goto cleanup_asn2rsapri;
2N/A }
2N/A (void) ber_scanf(p8obj_asn, "s", /* "s}" ? */
2N/A key_octs.bv_val, &key_octs.bv_len);
2N/A
2N/A /* Decode key octet string into softtoken key object. */
2N/A if ((key_asn = ber_init(&key_octs)) == NULLBER) {
2N/A rv = CKR_GENERAL_ERROR;
2N/A goto cleanup_asn2rsapri;
2N/A }
2N/A
2N/A /* ... begin-sequence { version, */
2N/A if (ber_first_element(key_asn, &size, &cookie) != LBER_INTEGER) {
2N/A rv = CKR_WRAPPED_KEY_INVALID;
2N/A goto cleanup_asn2rsapri;
2N/A }
2N/A (void) ber_scanf(key_asn, "i", &version); /* "{i" ? */
2N/A
2N/A /* ... modulus, */
2N/A if (ber_next_element(key_asn, &size, cookie) != LBER_INTEGER) {
2N/A rv = CKR_WRAPPED_KEY_INVALID;
2N/A goto cleanup_asn2rsapri;
2N/A }
2N/A if (size > MAX_RSA_KEY) {
2N/A rv = CKR_FUNCTION_NOT_SUPPORTED;
2N/A goto cleanup_asn2rsapri;
2N/A }
2N/A tmplen = size + 1;
2N/A if ((tmp.big_value = malloc(tmplen)) == NULL) {
2N/A rv = CKR_HOST_MEMORY;
2N/A goto cleanup_asn2rsapri;
2N/A }
2N/A (void) ber_scanf(key_asn, "s", tmp.big_value, &tmplen);
2N/A tmp.big_value_len = tmplen;
2N/A if ((rv = unpad_bigint_attr(tmp, &tmp_nopad)) != CKR_OK) {
2N/A free(tmp.big_value);
2N/A goto cleanup_asn2rsapri;
2N/A }
2N/A free(tmp.big_value);
2N/A copy_bigint_attr(&tmp_nopad, KEY_PRI_RSA_MOD(keyp));
2N/A
2N/A /* ... public exponent, */
2N/A if (ber_next_element(key_asn, &size, cookie) != LBER_INTEGER) {
2N/A rv = CKR_WRAPPED_KEY_INVALID;
2N/A goto error_asn2rsapri;
2N/A }
2N/A if (size > MAX_RSA_KEY) {
2N/A rv = CKR_FUNCTION_NOT_SUPPORTED;
2N/A goto error_asn2rsapri;
2N/A }
2N/A tmplen = size + 1;
2N/A if ((tmp.big_value = malloc(tmplen)) == NULL) {
2N/A rv = CKR_HOST_MEMORY;
2N/A goto error_asn2rsapri;
2N/A }
2N/A (void) ber_scanf(key_asn, "s", tmp.big_value, &tmplen);
2N/A tmp.big_value_len = tmplen;
2N/A if ((rv = unpad_bigint_attr(tmp, &tmp_nopad)) != CKR_OK) {
2N/A free(tmp.big_value);
2N/A goto error_asn2rsapri;
2N/A }
2N/A free(tmp.big_value);
2N/A copy_bigint_attr(&tmp_nopad, KEY_PRI_RSA_PUBEXPO(keyp));
2N/A
2N/A /* ... private exponent, */
2N/A if (ber_next_element(key_asn, &size, cookie) != LBER_INTEGER) {
2N/A rv = CKR_WRAPPED_KEY_INVALID;
2N/A goto error_asn2rsapri;
2N/A }
2N/A if (size > MAX_RSA_KEY) {
2N/A rv = CKR_FUNCTION_NOT_SUPPORTED;
2N/A goto error_asn2rsapri;
2N/A }
2N/A tmplen = size + 1;
2N/A if ((tmp.big_value = malloc(tmplen)) == NULL) {
2N/A rv = CKR_HOST_MEMORY;
2N/A goto error_asn2rsapri;
2N/A }
2N/A (void) ber_scanf(key_asn, "s", tmp.big_value, &tmplen);
2N/A tmp.big_value_len = tmplen;
2N/A if ((rv = unpad_bigint_attr(tmp, &tmp_nopad)) != CKR_OK) {
2N/A free(tmp.big_value);
2N/A goto error_asn2rsapri;
2N/A }
2N/A free(tmp.big_value);
2N/A copy_bigint_attr(&tmp_nopad, KEY_PRI_RSA_PRIEXPO(keyp));
2N/A
2N/A /* ... prime 1, */
2N/A if (ber_next_element(key_asn, &size, cookie) != LBER_INTEGER) {
2N/A rv = CKR_WRAPPED_KEY_INVALID;
2N/A goto error_asn2rsapri;
2N/A }
2N/A if (size > MAX_RSA_KEY) {
2N/A rv = CKR_FUNCTION_NOT_SUPPORTED;
2N/A goto error_asn2rsapri;
2N/A }
2N/A tmplen = size + 1;
2N/A if ((tmp.big_value = malloc(tmplen)) == NULL) {
2N/A rv = CKR_HOST_MEMORY;
2N/A goto error_asn2rsapri;
2N/A }
2N/A (void) ber_scanf(key_asn, "s", tmp.big_value, &tmplen);
2N/A tmp.big_value_len = tmplen;
2N/A if ((rv = unpad_bigint_attr(tmp, &tmp_nopad)) != CKR_OK) {
2N/A free(tmp.big_value);
2N/A goto error_asn2rsapri;
2N/A }
2N/A free(tmp.big_value);
2N/A copy_bigint_attr(&tmp_nopad, KEY_PRI_RSA_PRIME1(keyp));
2N/A
2N/A /* ... prime 2, */
2N/A if (ber_next_element(key_asn, &size, cookie) != LBER_INTEGER) {
2N/A rv = CKR_WRAPPED_KEY_INVALID;
2N/A goto error_asn2rsapri;
2N/A }
2N/A if (size > MAX_RSA_KEY) {
2N/A rv = CKR_FUNCTION_NOT_SUPPORTED;
2N/A goto error_asn2rsapri;
2N/A }
2N/A tmplen = size + 1;
2N/A if ((tmp.big_value = malloc(tmplen)) == NULL) {
2N/A rv = CKR_HOST_MEMORY;
2N/A goto error_asn2rsapri;
2N/A }
2N/A (void) ber_scanf(key_asn, "s", tmp.big_value, &tmplen);
2N/A tmp.big_value_len = tmplen;
2N/A if ((rv = unpad_bigint_attr(tmp, &tmp_nopad)) != CKR_OK) {
2N/A free(tmp.big_value);
2N/A goto error_asn2rsapri;
2N/A }
2N/A free(tmp.big_value);
2N/A copy_bigint_attr(&tmp_nopad, KEY_PRI_RSA_PRIME2(keyp));
2N/A
2N/A /* ... exponent 1, */
2N/A if (ber_next_element(key_asn, &size, cookie) != LBER_INTEGER) {
2N/A rv = CKR_WRAPPED_KEY_INVALID;
2N/A goto error_asn2rsapri;
2N/A }
2N/A if (size > MAX_RSA_KEY) {
2N/A rv = CKR_FUNCTION_NOT_SUPPORTED;
2N/A goto error_asn2rsapri;
2N/A }
2N/A tmplen = size + 1;
2N/A if ((tmp.big_value = malloc(tmplen)) == NULL) {
2N/A rv = CKR_HOST_MEMORY;
2N/A goto error_asn2rsapri;
2N/A }
2N/A (void) ber_scanf(key_asn, "s", tmp.big_value, &tmplen);
2N/A tmp.big_value_len = tmplen;
2N/A if ((rv = unpad_bigint_attr(tmp, &tmp_nopad)) != CKR_OK) {
2N/A free(tmp.big_value);
2N/A goto error_asn2rsapri;
2N/A }
2N/A free(tmp.big_value);
2N/A copy_bigint_attr(&tmp_nopad, KEY_PRI_RSA_EXPO1(keyp));
2N/A
2N/A /* ... exponent 2, */
2N/A if (ber_next_element(key_asn, &size, cookie) != LBER_INTEGER) {
2N/A rv = CKR_WRAPPED_KEY_INVALID;
2N/A goto error_asn2rsapri;
2N/A }
2N/A if (size > MAX_RSA_KEY) {
2N/A rv = CKR_FUNCTION_NOT_SUPPORTED;
2N/A goto error_asn2rsapri;
2N/A }
2N/A tmplen = size + 1;
2N/A if ((tmp.big_value = malloc(tmplen)) == NULL) {
2N/A rv = CKR_HOST_MEMORY;
2N/A goto error_asn2rsapri;
2N/A }
2N/A (void) ber_scanf(key_asn, "s", tmp.big_value, &tmplen);
2N/A tmp.big_value_len = tmplen;
2N/A if ((rv = unpad_bigint_attr(tmp, &tmp_nopad)) != CKR_OK) {
2N/A free(tmp.big_value);
2N/A goto error_asn2rsapri;
2N/A }
2N/A free(tmp.big_value);
2N/A copy_bigint_attr(&tmp_nopad, KEY_PRI_RSA_EXPO2(keyp));
2N/A
2N/A /* ... coefficient } end-sequence */
2N/A if (ber_next_element(key_asn, &size, cookie) != LBER_INTEGER) {
2N/A rv = CKR_WRAPPED_KEY_INVALID;
2N/A goto error_asn2rsapri;
2N/A }
2N/A if (size > MAX_RSA_KEY) {
2N/A rv = CKR_FUNCTION_NOT_SUPPORTED;
2N/A goto error_asn2rsapri;
2N/A }
2N/A tmplen = size + 1;
2N/A if ((tmp.big_value = malloc(tmplen)) == NULL) {
2N/A rv = CKR_HOST_MEMORY;
2N/A goto error_asn2rsapri;
2N/A }
2N/A (void) ber_scanf(key_asn, "s", /* "s}" ? */
2N/A tmp.big_value, &tmplen);
2N/A tmp.big_value_len = tmplen;
2N/A if ((rv = unpad_bigint_attr(tmp, &tmp_nopad)) != CKR_OK) {
2N/A free(tmp.big_value);
2N/A goto error_asn2rsapri;
2N/A }
2N/A free(tmp.big_value);
2N/A copy_bigint_attr(&tmp_nopad, KEY_PRI_RSA_COEF(keyp));
2N/A
2N/A goto cleanup_asn2rsapri;
2N/A
2N/Aerror_asn2rsapri:
2N/A
2N/A bigint_attr_cleanup(KEY_PRI_RSA_MOD(keyp));
2N/A bigint_attr_cleanup(KEY_PRI_RSA_PUBEXPO(keyp));
2N/A bigint_attr_cleanup(KEY_PRI_RSA_PRIEXPO(keyp));
2N/A bigint_attr_cleanup(KEY_PRI_RSA_PRIME1(keyp));
2N/A bigint_attr_cleanup(KEY_PRI_RSA_PRIME2(keyp));
2N/A bigint_attr_cleanup(KEY_PRI_RSA_EXPO1(keyp));
2N/A bigint_attr_cleanup(KEY_PRI_RSA_EXPO2(keyp));
2N/A bigint_attr_cleanup(KEY_PRI_RSA_COEF(keyp));
2N/A
2N/Acleanup_asn2rsapri:
2N/A
2N/A if (tmp_nopad.big_value != NULL) {
2N/A (void) memset(tmp_nopad.big_value, 0x0,
2N/A tmp_nopad.big_value_len);
2N/A free(tmp_nopad.big_value);
2N/A }
2N/A
2N/A if (p8obj_asn != NULLBER)
2N/A ber_free(p8obj_asn, 1);
2N/A
2N/A if (key_octs.bv_val != NULL)
2N/A free(key_octs.bv_val);
2N/A
2N/A if (key_asn != NULLBER)
2N/A ber_free(key_asn, 1);
2N/A
2N/A return (rv);
2N/A}
2N/A
2N/A/* Decode ASN.1 BER syntax into DSA private key. */
2N/Astatic CK_RV
2N/Aasn1_to_dsa_pri(private_key_obj_t *keyp, uchar_t *buf, ulong_t buf_len)
2N/A{
2N/A CK_RV rv = CKR_OK;
2N/A BerValue p8obj_octs, key_octs;
2N/A BerElement *p8obj_asn = NULLBER, *key_asn = NULLBER;
2N/A ber_len_t size, tmplen;
2N/A char *cookie;
2N/A int version;
2N/A uchar_t oid[sizeof (DSA_OID) + 1];
2N/A biginteger_t tmp, tmp_nopad = { NULL, 0 };
2N/A
2N/A p8obj_octs.bv_val = (char *)buf;
2N/A#ifdef _LP64
2N/A /* LINTED E_CAST_INT_TO_SMALL_INT */
2N/A p8obj_octs.bv_len = (ber_len_t)buf_len;
2N/A#else
2N/A p8obj_octs.bv_len = (ber_len_t)buf_len;
2N/A#endif
2N/A
2N/A key_octs.bv_val = NULL;
2N/A key_octs.bv_len = 0;
2N/A
2N/A /* Decode PKCS#8 object ASN.1, verifying it is DSA private key. */
2N/A if ((p8obj_asn = ber_init(&p8obj_octs)) == NULLBER)
2N/A return (CKR_GENERAL_ERROR);
2N/A
2N/A /* PKCS#8 PrivateKeyInfo ... */
2N/A if (ber_first_element(p8obj_asn, &size, &cookie) != LBER_INTEGER) {
2N/A rv = CKR_WRAPPED_KEY_INVALID;
2N/A goto cleanup_asn2dsapri;
2N/A }
2N/A /* ... begin-sequence { version, */
2N/A (void) ber_scanf(p8obj_asn, "i", &version); /* "{i" ? */
2N/A
2N/A if (ber_next_element(p8obj_asn, &size, cookie) != LBER_SEQUENCE) {
2N/A rv = CKR_WRAPPED_KEY_INVALID;
2N/A goto cleanup_asn2dsapri;
2N/A }
2N/A /* ... begin-sequence { */
2N/A (void) ber_scanf(p8obj_asn, "{");
2N/A
2N/A if (ber_next_element(p8obj_asn, &size, cookie) != OID_TAG) {
2N/A rv = CKR_WRAPPED_KEY_INVALID;
2N/A goto cleanup_asn2dsapri;
2N/A }
2N/A /* ... OID, \* DSA algorithm OID *\ */
2N/A if (size != sizeof (DSA_OID)) {
2N/A rv = CKR_FUNCTION_NOT_SUPPORTED;
2N/A goto cleanup_asn2dsapri;
2N/A }
2N/A size = sizeof (oid);
2N/A (void) ber_scanf(p8obj_asn, "s", oid, &size);
2N/A if (memcmp(oid, DSA_OID, size) != 0) {
2N/A rv = CKR_FUNCTION_NOT_SUPPORTED;
2N/A goto cleanup_asn2dsapri;
2N/A }
2N/A
2N/A if (ber_next_element(p8obj_asn, &size, cookie) != LBER_SEQUENCE) {
2N/A rv = CKR_WRAPPED_KEY_INVALID;
2N/A goto cleanup_asn2dsapri;
2N/A }
2N/A /* ... begin-sequence { */
2N/A (void) ber_scanf(p8obj_asn, "{");
2N/A
2N/A if (ber_next_element(p8obj_asn, &size, cookie) != LBER_INTEGER) {
2N/A rv = CKR_WRAPPED_KEY_INVALID;
2N/A goto cleanup_asn2dsapri;
2N/A }
2N/A /* ... prime, */
2N/A /* Length may be padded 1 byte to keep positive if 1st byte >= 0x80. */
2N/A if (size > MAX_DSA_KEY_LEN_BYTES + 1) {
2N/A rv = CKR_FUNCTION_NOT_SUPPORTED;
2N/A goto cleanup_asn2dsapri;
2N/A }
2N/A tmplen = size + 1;
2N/A if ((tmp.big_value = malloc(tmplen)) == NULL) {
2N/A rv = CKR_HOST_MEMORY;
2N/A goto cleanup_asn2dsapri;
2N/A }
2N/A (void) ber_scanf(p8obj_asn, "s", tmp.big_value, &tmplen);
2N/A tmp.big_value_len = tmplen;
2N/A if ((rv = unpad_bigint_attr(tmp, &tmp_nopad)) != CKR_OK) {
2N/A free(tmp.big_value);
2N/A goto cleanup_asn2dsapri;
2N/A }
2N/A free(tmp.big_value);
2N/A copy_bigint_attr(&tmp_nopad, KEY_PRI_DSA_PRIME(keyp));
2N/A
2N/A if (ber_next_element(p8obj_asn, &size, cookie) != LBER_INTEGER) {
2N/A rv = CKR_WRAPPED_KEY_INVALID;
2N/A goto error_asn2dsapri;
2N/A }
2N/A /* ... subprime, */
2N/A /* Length may be padded 1 byte to keep positive if 1st byte >= 0x80. */
2N/A if (size > MAX_DSA_SUBPRIME_BYTES + 1) {
2N/A rv = CKR_FUNCTION_NOT_SUPPORTED;
2N/A goto error_asn2dsapri;
2N/A }
2N/A tmplen = size + 1;
2N/A if ((tmp.big_value = malloc(tmplen)) == NULL) {
2N/A rv = CKR_HOST_MEMORY;
2N/A goto error_asn2dsapri;
2N/A }
2N/A (void) ber_scanf(p8obj_asn, "s", tmp.big_value, &tmplen);
2N/A tmp.big_value_len = tmplen;
2N/A if ((rv = unpad_bigint_attr(tmp, &tmp_nopad)) != CKR_OK) {
2N/A free(tmp.big_value);
2N/A goto error_asn2dsapri;
2N/A }
2N/A free(tmp.big_value);
2N/A copy_bigint_attr(&tmp_nopad, KEY_PRI_DSA_SUBPRIME(keyp));
2N/A
2N/A if (ber_next_element(p8obj_asn, &size, cookie) != LBER_INTEGER) {
2N/A rv = CKR_WRAPPED_KEY_INVALID;
2N/A goto error_asn2dsapri;
2N/A }
2N/A /* ... base } end-sequence } end-sequence */
2N/A /* Length may be padded 1 byte to keep positive if 1st byte >= 0x80. */
2N/A if (size > MAX_DSA_KEY_LEN_BYTES + 1) {
2N/A rv = CKR_FUNCTION_NOT_SUPPORTED;
2N/A goto error_asn2dsapri;
2N/A }
2N/A tmplen = size + 1;
2N/A if ((tmp.big_value = malloc(tmplen)) == NULL) {
2N/A rv = CKR_HOST_MEMORY;
2N/A goto error_asn2dsapri;
2N/A }
2N/A (void) ber_scanf(p8obj_asn, "s", /* "s}}" ? */
2N/A tmp.big_value, &tmplen);
2N/A tmp.big_value_len = tmplen;
2N/A if ((rv = unpad_bigint_attr(tmp, &tmp_nopad)) != CKR_OK) {
2N/A free(tmp.big_value);
2N/A goto error_asn2dsapri;
2N/A }
2N/A free(tmp.big_value);
2N/A copy_bigint_attr(&tmp_nopad, KEY_PRI_DSA_BASE(keyp));
2N/A
2N/A if (ber_next_element(p8obj_asn, &size, cookie) != LBER_OCTETSTRING) {
2N/A rv = CKR_WRAPPED_KEY_INVALID;
2N/A goto error_asn2dsapri;
2N/A }
2N/A /* ... DSAPrivateKey } end-sequence */
2N/A key_octs.bv_len = size + 1;
2N/A if ((key_octs.bv_val = malloc(size + 1)) == NULL) {
2N/A rv = CKR_HOST_MEMORY;
2N/A goto error_asn2dsapri;
2N/A }
2N/A (void) ber_scanf(p8obj_asn, "s", /* "s}" ? */
2N/A key_octs.bv_val, &key_octs.bv_len);
2N/A
2N/A /* Decode key octet string into softtoken key object. */
2N/A if ((key_asn = ber_init(&key_octs)) == NULLBER) {
2N/A rv = CKR_GENERAL_ERROR;
2N/A goto error_asn2dsapri;
2N/A }
2N/A
2N/A if (ber_next_element(key_asn, &size, cookie) != LBER_INTEGER) {
2N/A rv = CKR_WRAPPED_KEY_INVALID;
2N/A goto error_asn2dsapri;
2N/A }
2N/A /* ... value } end-sequence */
2N/A /* Length may be padded 1 byte to keep positive if 1st byte >= 0x80. */
2N/A if (size > MAX_DSA_SUBPRIME_BYTES + 1) {
2N/A rv = CKR_FUNCTION_NOT_SUPPORTED;
2N/A goto error_asn2dsapri;
2N/A }
2N/A tmplen = size + 1;
2N/A if ((tmp.big_value = malloc(tmplen)) == NULL) {
2N/A rv = CKR_HOST_MEMORY;
2N/A goto error_asn2dsapri;
2N/A }
2N/A (void) ber_scanf(key_asn, "s", /* "s}" ? */
2N/A tmp.big_value, &tmplen);
2N/A tmp.big_value_len = tmplen;
2N/A if ((rv = unpad_bigint_attr(tmp, &tmp_nopad)) != CKR_OK) {
2N/A free(tmp.big_value);
2N/A goto error_asn2dsapri;
2N/A }
2N/A free(tmp.big_value);
2N/A copy_bigint_attr(&tmp_nopad, KEY_PRI_DSA_VALUE(keyp));
2N/A
2N/A goto cleanup_asn2dsapri;
2N/A
2N/Aerror_asn2dsapri:
2N/A
2N/A bigint_attr_cleanup(KEY_PRI_DSA_PRIME(keyp));
2N/A bigint_attr_cleanup(KEY_PRI_DSA_SUBPRIME(keyp));
2N/A bigint_attr_cleanup(KEY_PRI_DSA_BASE(keyp));
2N/A bigint_attr_cleanup(KEY_PRI_DSA_VALUE(keyp));
2N/A
2N/Acleanup_asn2dsapri:
2N/A
2N/A if (tmp_nopad.big_value != NULL) {
2N/A (void) memset(tmp_nopad.big_value, 0x0,
2N/A tmp_nopad.big_value_len);
2N/A free(tmp_nopad.big_value);
2N/A }
2N/A
2N/A if (p8obj_asn != NULLBER)
2N/A ber_free(p8obj_asn, 1);
2N/A
2N/A if (key_octs.bv_val != NULL)
2N/A free(key_octs.bv_val);
2N/A
2N/A if (key_asn != NULLBER)
2N/A ber_free(key_asn, 1);
2N/A
2N/A return (rv);
2N/A}
2N/A
2N/A/* Decode ASN.1 BER syntax into DH private key. */
2N/Astatic CK_RV
2N/Aasn1_to_dh_pri(private_key_obj_t *keyp, uchar_t *buf, ulong_t buf_len)
2N/A{
2N/A CK_RV rv = CKR_OK;
2N/A BerValue p8obj_octs, key_octs;
2N/A BerElement *p8obj_asn = NULLBER, *key_asn = NULLBER;
2N/A ber_len_t size, tmplen;
2N/A char *cookie;
2N/A int version;
2N/A uchar_t oid[sizeof (DH_OID) + 1];
2N/A biginteger_t tmp, tmp_nopad = { NULL, 0 };
2N/A
2N/A p8obj_octs.bv_val = (char *)buf;
2N/A#ifdef _LP64
2N/A /* LINTED E_CAST_INT_TO_SMALL_INT */
2N/A p8obj_octs.bv_len = (ber_len_t)buf_len;
2N/A#else
2N/A p8obj_octs.bv_len = (ber_len_t)buf_len;
2N/A#endif
2N/A
2N/A key_octs.bv_val = NULL;
2N/A key_octs.bv_len = 0;
2N/A
2N/A /* Decode PKCS#8 object ASN.1, verifying it is DH private key. */
2N/A if ((p8obj_asn = ber_init(&p8obj_octs)) == NULLBER)
2N/A return (CKR_GENERAL_ERROR);
2N/A
2N/A /* PKCS#8 PrivateKeyInfo ... */
2N/A if (ber_first_element(p8obj_asn, &size, &cookie) != LBER_INTEGER) {
2N/A rv = CKR_WRAPPED_KEY_INVALID;
2N/A goto cleanup_asn2dhpri;
2N/A }
2N/A /* ... begin-sequence { version, */
2N/A (void) ber_scanf(p8obj_asn, "i", &version); /* "{i" ? */
2N/A
2N/A if (ber_next_element(p8obj_asn, &size, cookie) != LBER_SEQUENCE) {
2N/A rv = CKR_WRAPPED_KEY_INVALID;
2N/A goto cleanup_asn2dhpri;
2N/A }
2N/A /* ... begin-sequence { */
2N/A (void) ber_scanf(p8obj_asn, "{");
2N/A
2N/A if (ber_next_element(p8obj_asn, &size, cookie) != OID_TAG) {
2N/A rv = CKR_WRAPPED_KEY_INVALID;
2N/A goto cleanup_asn2dhpri;
2N/A }
2N/A /* ... OID, \* DH algorithm OID *\ */
2N/A if (size != sizeof (DH_OID)) {
2N/A rv = CKR_FUNCTION_NOT_SUPPORTED;
2N/A goto cleanup_asn2dhpri;
2N/A }
2N/A size = sizeof (oid);
2N/A (void) ber_scanf(p8obj_asn, "s", oid, &size);
2N/A if (memcmp(oid, DH_OID, size) != 0) {
2N/A rv = CKR_FUNCTION_NOT_SUPPORTED;
2N/A goto cleanup_asn2dhpri;
2N/A }
2N/A
2N/A if (ber_next_element(p8obj_asn, &size, cookie) != LBER_SEQUENCE) {
2N/A rv = CKR_WRAPPED_KEY_INVALID;
2N/A goto cleanup_asn2dhpri;
2N/A }
2N/A /* ... begin-sequence { */
2N/A (void) ber_scanf(p8obj_asn, "{");
2N/A
2N/A if (ber_next_element(p8obj_asn, &size, cookie) != LBER_INTEGER) {
2N/A rv = CKR_WRAPPED_KEY_INVALID;
2N/A goto cleanup_asn2dhpri;
2N/A }
2N/A /* ... prime, */
2N/A if (size > MAX_DH_KEYLENGTH_IN_BYTES) {
2N/A rv = CKR_FUNCTION_NOT_SUPPORTED;
2N/A goto cleanup_asn2dhpri;
2N/A }
2N/A tmplen = size + 1;
2N/A if ((tmp.big_value = malloc(tmplen)) == NULL) {
2N/A rv = CKR_HOST_MEMORY;
2N/A goto cleanup_asn2dhpri;
2N/A }
2N/A (void) ber_scanf(p8obj_asn, "s", tmp.big_value, &tmplen);
2N/A tmp.big_value_len = tmplen;
2N/A if ((rv = unpad_bigint_attr(tmp, &tmp_nopad)) != CKR_OK) {
2N/A free(tmp.big_value);
2N/A goto cleanup_asn2dhpri;
2N/A }
2N/A free(tmp.big_value);
2N/A copy_bigint_attr(&tmp_nopad, KEY_PRI_DH_PRIME(keyp));
2N/A
2N/A if (ber_next_element(p8obj_asn, &size, cookie) != LBER_INTEGER) {
2N/A rv = CKR_WRAPPED_KEY_INVALID;
2N/A goto error_asn2dhpri;
2N/A }
2N/A /* ... base } end-sequence } end-sequence */
2N/A if (size > MAX_DH_KEYLENGTH_IN_BYTES) {
2N/A rv = CKR_FUNCTION_NOT_SUPPORTED;
2N/A goto error_asn2dhpri;
2N/A }
2N/A tmplen = size + 1;
2N/A if ((tmp.big_value = malloc(tmplen)) == NULL) {
2N/A rv = CKR_HOST_MEMORY;
2N/A goto error_asn2dhpri;
2N/A }
2N/A (void) ber_scanf(p8obj_asn, "s", /* "s}}" ? */
2N/A tmp.big_value, &tmplen);
2N/A tmp.big_value_len = tmplen;
2N/A if ((rv = unpad_bigint_attr(tmp, &tmp_nopad)) != CKR_OK) {
2N/A free(tmp.big_value);
2N/A goto error_asn2dhpri;
2N/A }
2N/A free(tmp.big_value);
2N/A copy_bigint_attr(&tmp_nopad, KEY_PRI_DH_BASE(keyp));
2N/A
2N/A if (ber_next_element(p8obj_asn, &size, cookie) != LBER_OCTETSTRING) {
2N/A rv = CKR_WRAPPED_KEY_INVALID;
2N/A goto error_asn2dhpri;
2N/A }
2N/A /* ... DHPrivateKey } end-sequence */
2N/A key_octs.bv_len = size + 1;
2N/A if ((key_octs.bv_val = malloc(size + 1)) == NULL) {
2N/A rv = CKR_HOST_MEMORY;
2N/A goto error_asn2dhpri;
2N/A }
2N/A (void) ber_scanf(p8obj_asn, "s", /* "s}" ? */
2N/A key_octs.bv_val, &key_octs.bv_len);
2N/A
2N/A /* Decode key octet string into softtoken key object. */
2N/A if ((key_asn = ber_init(&key_octs)) == NULLBER) {
2N/A rv = CKR_GENERAL_ERROR;
2N/A goto error_asn2dhpri;
2N/A }
2N/A
2N/A if (ber_next_element(key_asn, &size, cookie) != LBER_INTEGER) {
2N/A rv = CKR_WRAPPED_KEY_INVALID;
2N/A goto error_asn2dhpri;
2N/A }
2N/A /* ... value } end-sequence */
2N/A if (size > MAX_DH_KEYLENGTH_IN_BYTES) {
2N/A rv = CKR_FUNCTION_NOT_SUPPORTED;
2N/A goto error_asn2dhpri;
2N/A }
2N/A tmplen = size + 1;
2N/A if ((tmp.big_value = malloc(tmplen)) == NULL) {
2N/A rv = CKR_HOST_MEMORY;
2N/A goto error_asn2dhpri;
2N/A }
2N/A (void) ber_scanf(key_asn, "s", /* "s}" ? */
2N/A tmp.big_value, &tmplen);
2N/A tmp.big_value_len = tmplen;
2N/A if ((rv = unpad_bigint_attr(tmp, &tmp_nopad)) != CKR_OK) {
2N/A free(tmp.big_value);
2N/A goto error_asn2dhpri;
2N/A }
2N/A free(tmp.big_value);
2N/A copy_bigint_attr(&tmp_nopad, KEY_PRI_DH_VALUE(keyp));
2N/A KEY_PRI_DH_VAL_BITS(keyp) = bigint_bitlen(KEY_PRI_DH_VALUE(keyp));
2N/A
2N/A goto cleanup_asn2dhpri;
2N/A
2N/Aerror_asn2dhpri:
2N/A
2N/A bigint_attr_cleanup(KEY_PRI_DH_PRIME(keyp));
2N/A bigint_attr_cleanup(KEY_PRI_DH_BASE(keyp));
2N/A bigint_attr_cleanup(KEY_PRI_DH_VALUE(keyp));
2N/A
2N/Acleanup_asn2dhpri:
2N/A
2N/A if (tmp_nopad.big_value != NULL) {
2N/A (void) memset(tmp_nopad.big_value, 0x0,
2N/A tmp_nopad.big_value_len);
2N/A free(tmp_nopad.big_value);
2N/A }
2N/A
2N/A if (p8obj_asn != NULLBER)
2N/A ber_free(p8obj_asn, 1);
2N/A
2N/A if (key_octs.bv_val != NULL)
2N/A free(key_octs.bv_val);
2N/A
2N/A if (key_asn != NULLBER)
2N/A ber_free(key_asn, 1);
2N/A
2N/A return (rv);
2N/A}
2N/A
2N/A/* Decode ASN.1 BER syntax into DH X9.42 private key. */
2N/Astatic CK_RV
2N/Aasn1_to_x942_dh_pri(private_key_obj_t *keyp, uchar_t *buf, ulong_t buf_len)
2N/A{
2N/A CK_RV rv = CKR_OK;
2N/A BerValue p8obj_octs, key_octs;
2N/A BerElement *p8obj_asn = NULLBER, *key_asn = NULLBER;
2N/A ber_len_t size, tmplen;
2N/A char *cookie;
2N/A int version;
2N/A uchar_t oid[sizeof (DH942_OID) + 1];
2N/A biginteger_t tmp, tmp_nopad = { NULL, 0 };
2N/A
2N/A p8obj_octs.bv_val = (char *)buf;
2N/A#ifdef _LP64
2N/A /* LINTED E_CAST_INT_TO_SMALL_INT */
2N/A p8obj_octs.bv_len = (ber_len_t)buf_len;
2N/A#else
2N/A p8obj_octs.bv_len = (ber_len_t)buf_len;
2N/A#endif
2N/A
2N/A key_octs.bv_val = NULL;
2N/A key_octs.bv_len = 0;
2N/A
2N/A /* Decode PKCS#8 object ASN.1, verifying it is DH X9.42 private key. */
2N/A if ((p8obj_asn = ber_init(&p8obj_octs)) == NULLBER)
2N/A return (CKR_GENERAL_ERROR);
2N/A
2N/A /* PKCS#8 PrivateKeyInfo ... */
2N/A if (ber_first_element(p8obj_asn, &size, &cookie) != LBER_INTEGER) {
2N/A rv = CKR_WRAPPED_KEY_INVALID;
2N/A goto cleanup_asn2x942dhpri;
2N/A }
2N/A /* ... begin-sequence { version, */
2N/A (void) ber_scanf(p8obj_asn, "i", &version); /* "{i" ? */
2N/A
2N/A if (ber_next_element(p8obj_asn, &size, cookie) != LBER_SEQUENCE) {
2N/A rv = CKR_WRAPPED_KEY_INVALID;
2N/A goto cleanup_asn2x942dhpri;
2N/A }
2N/A /* ... begin-sequence { */
2N/A (void) ber_scanf(p8obj_asn, "{");
2N/A
2N/A if (ber_next_element(p8obj_asn, &size, cookie) != OID_TAG) {
2N/A rv = CKR_WRAPPED_KEY_INVALID;
2N/A goto cleanup_asn2x942dhpri;
2N/A }
2N/A /* ... OID, \* DH X9.42 algorithm OID *\ */
2N/A if (size != sizeof (DH942_OID)) {
2N/A rv = CKR_FUNCTION_NOT_SUPPORTED;
2N/A goto cleanup_asn2x942dhpri;
2N/A }
2N/A size = sizeof (oid);
2N/A (void) ber_scanf(p8obj_asn, "s", oid, &size);
2N/A if (memcmp(oid, DH942_OID, size) != 0) {
2N/A rv = CKR_FUNCTION_NOT_SUPPORTED;
2N/A goto cleanup_asn2x942dhpri;
2N/A }
2N/A
2N/A if (ber_next_element(p8obj_asn, &size, cookie) != LBER_SEQUENCE) {
2N/A rv = CKR_WRAPPED_KEY_INVALID;
2N/A goto cleanup_asn2x942dhpri;
2N/A }
2N/A /* ... begin-sequence { */
2N/A (void) ber_scanf(p8obj_asn, "{");
2N/A
2N/A if (ber_next_element(p8obj_asn, &size, cookie) != LBER_INTEGER) {
2N/A rv = CKR_WRAPPED_KEY_INVALID;
2N/A goto cleanup_asn2x942dhpri;
2N/A }
2N/A /* ... prime, */
2N/A if (size > MAX_DH_KEYLENGTH_IN_BYTES) {
2N/A rv = CKR_FUNCTION_NOT_SUPPORTED;
2N/A goto cleanup_asn2x942dhpri;
2N/A }
2N/A tmplen = size + 1;
2N/A if ((tmp.big_value = malloc(tmplen)) == NULL) {
2N/A rv = CKR_HOST_MEMORY;
2N/A goto cleanup_asn2x942dhpri;
2N/A }
2N/A (void) ber_scanf(p8obj_asn, "s", tmp.big_value, &tmplen);
2N/A tmp.big_value_len = tmplen;
2N/A if ((rv = unpad_bigint_attr(tmp, &tmp_nopad)) != CKR_OK) {
2N/A free(tmp.big_value);
2N/A goto cleanup_asn2x942dhpri;
2N/A }
2N/A free(tmp.big_value);
2N/A copy_bigint_attr(&tmp_nopad, KEY_PRI_DH942_PRIME(keyp));
2N/A
2N/A if (ber_next_element(p8obj_asn, &size, cookie) != LBER_INTEGER) {
2N/A rv = CKR_WRAPPED_KEY_INVALID;
2N/A goto error_asn2x942dhpri;
2N/A }
2N/A /* ... base, */
2N/A if (size > MAX_DH_KEYLENGTH_IN_BYTES) {
2N/A rv = CKR_FUNCTION_NOT_SUPPORTED;
2N/A goto error_asn2x942dhpri;
2N/A }
2N/A tmplen = size + 1;
2N/A if ((tmp.big_value = malloc(tmplen)) == NULL) {
2N/A rv = CKR_HOST_MEMORY;
2N/A goto error_asn2x942dhpri;
2N/A }
2N/A (void) ber_scanf(p8obj_asn, "s", tmp.big_value, &tmplen);
2N/A tmp.big_value_len = tmplen;
2N/A if ((rv = unpad_bigint_attr(tmp, &tmp_nopad)) != CKR_OK) {
2N/A free(tmp.big_value);
2N/A goto error_asn2x942dhpri;
2N/A }
2N/A free(tmp.big_value);
2N/A copy_bigint_attr(&tmp_nopad, KEY_PRI_DH942_BASE(keyp));
2N/A
2N/A if (ber_next_element(p8obj_asn, &size, cookie) != LBER_INTEGER) {
2N/A rv = CKR_WRAPPED_KEY_INVALID;
2N/A goto error_asn2x942dhpri;
2N/A }
2N/A /* ... subprime } end-sequence } end-sequence */
2N/A if (size > MAX_DH_KEYLENGTH_IN_BYTES) {
2N/A rv = CKR_FUNCTION_NOT_SUPPORTED;
2N/A goto error_asn2x942dhpri;
2N/A }
2N/A tmplen = size + 1;
2N/A if ((tmp.big_value = malloc(tmplen)) == NULL) {
2N/A rv = CKR_HOST_MEMORY;
2N/A goto error_asn2x942dhpri;
2N/A }
2N/A (void) ber_scanf(p8obj_asn, "s", /* "s}}" ? */
2N/A tmp.big_value, &tmplen);
2N/A tmp.big_value_len = tmplen;
2N/A if ((rv = unpad_bigint_attr(tmp, &tmp_nopad)) != CKR_OK) {
2N/A free(tmp.big_value);
2N/A goto error_asn2x942dhpri;
2N/A }
2N/A free(tmp.big_value);
2N/A copy_bigint_attr(&tmp_nopad, KEY_PRI_DH942_SUBPRIME(keyp));
2N/A
2N/A if (ber_next_element(p8obj_asn, &size, cookie) != LBER_OCTETSTRING) {
2N/A rv = CKR_WRAPPED_KEY_INVALID;
2N/A goto error_asn2x942dhpri;
2N/A }
2N/A /* ... DHPrivateKey } end-sequence */
2N/A key_octs.bv_len = size + 1;
2N/A if ((key_octs.bv_val = malloc(size + 1)) == NULL) {
2N/A rv = CKR_HOST_MEMORY;
2N/A goto error_asn2x942dhpri;
2N/A }
2N/A (void) ber_scanf(p8obj_asn, "s", /* "s}" ? */
2N/A key_octs.bv_val, &key_octs.bv_len);
2N/A
2N/A /* Decode key octet string into softtoken key object. */
2N/A if ((key_asn = ber_init(&key_octs)) == NULLBER) {
2N/A rv = CKR_GENERAL_ERROR;
2N/A goto error_asn2x942dhpri;
2N/A }
2N/A
2N/A if (ber_next_element(key_asn, &size, cookie) != LBER_INTEGER) {
2N/A rv = CKR_WRAPPED_KEY_INVALID;
2N/A goto error_asn2x942dhpri;
2N/A }
2N/A /* ... value } end-sequence */
2N/A if (size > MAX_DH_KEYLENGTH_IN_BYTES) {
2N/A rv = CKR_FUNCTION_NOT_SUPPORTED;
2N/A goto error_asn2x942dhpri;
2N/A }
2N/A tmplen = size + 1;
2N/A if ((tmp.big_value = malloc(tmplen)) == NULL) {
2N/A rv = CKR_HOST_MEMORY;
2N/A goto error_asn2x942dhpri;
2N/A }
2N/A (void) ber_scanf(key_asn, "s", /* "s}" ? */
2N/A tmp.big_value, &tmplen);
2N/A tmp.big_value_len = tmplen;
2N/A if ((rv = unpad_bigint_attr(tmp, &tmp_nopad)) != CKR_OK) {
2N/A free(tmp.big_value);
2N/A goto error_asn2x942dhpri;
2N/A }
2N/A free(tmp.big_value);
2N/A copy_bigint_attr(&tmp_nopad, KEY_PRI_DH942_VALUE(keyp));
2N/A
2N/A goto cleanup_asn2x942dhpri;
2N/A
2N/Aerror_asn2x942dhpri:
2N/A
2N/A bigint_attr_cleanup(KEY_PRI_DH942_PRIME(keyp));
2N/A bigint_attr_cleanup(KEY_PRI_DH942_BASE(keyp));
2N/A bigint_attr_cleanup(KEY_PRI_DH942_SUBPRIME(keyp));
2N/A bigint_attr_cleanup(KEY_PRI_DH942_VALUE(keyp));
2N/A
2N/Acleanup_asn2x942dhpri:
2N/A
2N/A if (tmp_nopad.big_value != NULL) {
2N/A (void) memset(tmp_nopad.big_value, 0x0,
2N/A tmp_nopad.big_value_len);
2N/A free(tmp_nopad.big_value);
2N/A }
2N/A
2N/A if (p8obj_asn != NULLBER)
2N/A ber_free(p8obj_asn, 1);
2N/A
2N/A if (key_octs.bv_val != NULL)
2N/A free(key_octs.bv_val);
2N/A
2N/A if (key_asn != NULLBER)
2N/A ber_free(key_asn, 1);
2N/A
2N/A return (rv);
2N/A}
2N/A
2N/A/*
2N/A * Decode the object key from ASN.1 format into soft_object_t.
2N/A */
2N/ACK_RV
2N/Asoft_asn1_to_object(soft_object_t *objp, uchar_t *buf, ulong_t buf_len)
2N/A{
2N/A CK_RV rv = CKR_OK;
2N/A CK_OBJECT_CLASS class = objp->class;
2N/A CK_KEY_TYPE keytype = objp->key_type;
2N/A private_key_obj_t *pvk;
2N/A
2N/A switch (class) {
2N/A
2N/A case CKO_PRIVATE_KEY:
2N/A /* Allocate storage for Private Key Object. */
2N/A if ((pvk = calloc(1, sizeof (private_key_obj_t))) == NULL) {
2N/A rv = CKR_HOST_MEMORY;
2N/A return (rv);
2N/A }
2N/A
2N/A switch (keytype) {
2N/A case CKK_RSA:
2N/A rv = asn1_to_rsa_pri(pvk, buf, buf_len);
2N/A break;
2N/A
2N/A case CKK_DSA:
2N/A rv = asn1_to_dsa_pri(pvk, buf, buf_len);
2N/A break;
2N/A
2N/A case CKK_DH:
2N/A rv = asn1_to_dh_pri(pvk, buf, buf_len);
2N/A break;
2N/A
2N/A case CKK_X9_42_DH:
2N/A rv = asn1_to_x942_dh_pri(pvk, buf, buf_len);
2N/A break;
2N/A
2N/A default:
2N/A rv = CKR_FUNCTION_NOT_SUPPORTED;
2N/A break;
2N/A
2N/A } /* keytype */
2N/A
2N/A if (rv != CKR_OK) {
2N/A free(pvk);
2N/A } else {
2N/A if (objp->object_class_u.private_key != NULL) {
2N/A soft_cleanup_object_bigint_attrs(objp);
2N/A }
2N/A objp->object_class_u.private_key = pvk;
2N/A }
2N/A break;
2N/A
2N/A default:
2N/A rv = CKR_FUNCTION_NOT_SUPPORTED;
2N/A break;
2N/A
2N/A } /* class */
2N/A
2N/A return (rv);
2N/A}