/*
* 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
* 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 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/sysmacros.h>
#include <des/des_impl.h>
#include <ecc/ecc_impl.h>
extern struct mod_ops mod_cryptoops;
/*
* Module linkage information for the kernel.
*/
"EC Kernel SW Provider"
};
(void *)&modlcrypto,
};
/*
* CSPI information (entry points, provider info, etc.)
*/
typedef enum ecc_mech_type {
/*
* Context for ECDSA mechanism.
*/
typedef struct ecc_ctx {
} ecc_ctx_t;
/*
* Context for ECDSA_SHA1 mechanism.
*/
typedef struct digest_ecc_ctx {
union {
} dctx_u;
/*
* Mechanism info structure passed to KCF during registration.
*/
/* EC_KEY_PAIR_GEN */
/* ECDH */
/* ECDSA */
/* ECDSA_SHA1 */
};
};
NULL,
NULL,
};
NULL,
NULL,
};
static int ecc_nostore_key_derive(crypto_provider_handle_t,
NULL,
};
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
};
"EC Software Provider",
{&modlinkage},
NULL,
sizeof (ecc_mech_info_tab)/sizeof (crypto_mech_info_t),
};
static int get_template_attr_ulong(crypto_object_attribute_t *,
static void ecc_free_context(crypto_ctx_t *);
static void free_ecprivkey(ECPrivateKey *);
int
_init(void)
{
int ret;
return (ret);
/* Register with KCF. If the registration fails, remove the module. */
(void) mod_remove(&modlinkage);
return (EACCES);
}
return (0);
}
int
_fini(void)
{
/* Unregister from KCF if module is registered */
if (ecc_prov_handle != NULL) {
return (EBUSY);
}
return (mod_remove(&modlinkage));
}
int
{
}
/* ARGSUSED */
static void
{
}
/*
* Return the index of an attribute of specified type found in
* the specified array of attributes. If the attribute cannot
* found, return -1.
*/
static int
{
int i;
for (i = 0; i < nattr; i++)
return (i);
return (-1);
}
/*
* Common function used by the get_template_attr_*() family of
* functions. Returns the value of the specified attribute of specified
* length. Returns CRYPTO_SUCCESS on success, CRYPTO_ATTRIBUTE_VALUE_INVALID
* if the length of the attribute does not match the specified length,
* or CRYPTO_ARGUMENTS_BAD if the attribute cannot be found.
*/
static int
{
int attr_idx;
return (CRYPTO_ARGUMENTS_BAD);
if (oa_value_len != value_len) {
return (CRYPTO_ATTRIBUTE_VALUE_INVALID);
}
return (CRYPTO_SUCCESS);
}
/*
* Get the value of a ulong_t attribute from the specified template.
*/
static int
{
}
/*
* Called from init routines to do basic sanity checks. Init routines,
* e.g. sign_init should fail rather than subsequent operations.
*/
static int
{
if (mech_type != ECDSA_SHA1_MECH_INFO_TYPE &&
return (CRYPTO_MECHANISM_INVALID);
return (CRYPTO_KEY_TYPE_INCONSISTENT);
}
switch (class) {
case CKO_PUBLIC_KEY:
&point_len)) != CRYPTO_SUCCESS) {
return (CRYPTO_TEMPLATE_INCOMPLETE);
}
return (CRYPTO_KEY_SIZE_RANGE);
break;
case CKO_PRIVATE_KEY:
&value_len)) != CRYPTO_SUCCESS) {
return (CRYPTO_TEMPLATE_INCOMPLETE);
}
return (CRYPTO_KEY_SIZE_RANGE);
break;
default:
return (CRYPTO_TEMPLATE_INCONSISTENT);
}
return (rv);
}
/*
* This function guarantees to return non-zero random numbers.
* random_get_pseudo_bytes(), may return zeros.
*/
int
{
int rv;
size_t i = 0;
return (rv);
/*
* Walk through the returned random numbers pointed by ran_out,
* and look for any random number which is zero.
* If we find zero, call random_get_pseudo_bytes() to generate
* another 32 random numbers pool. Replace any zeros in ran_out[]
* from the random number in pool.
*/
while (i < ran_len) {
if (ran_out[i] != 0) {
i++;
continue;
}
/*
* Note that it is 'while' so we are guaranteed a
* non-zero value on exit.
*/
if (ebc == 0) {
/* refresh extrarand */
extrarand_len = sizeof (extrarand);
extrarand_len)) != 0) {
return (rv);
}
ebc = extrarand_len;
}
/* Replace zero with byte from extrarand. */
-- ebc;
/*
* the next pass through the loop.
*/
}
return (CRYPTO_SUCCESS);
}
static void
{
else
}
}
/* ARGSUSED */
static int
{
int rv;
int kmflag;
¶ms_len)) {
return (CRYPTO_ARGUMENTS_BAD);
}
/* ASN1 check */
if (params[0] != 0x06 ||
return (CRYPTO_ATTRIBUTE_VALUE_INVALID);
}
/* bad curve OID */
return (CRYPTO_ARGUMENTS_BAD);
}
/*
* Allocate an ECC context.
*/
switch (mech_type) {
break;
default:
break;
}
return (CRYPTO_HOST_MEMORY);
}
kmflag)) != CRYPTO_SUCCESS) {
switch (mech_type) {
break;
default:
break;
}
return (rv);
}
switch (mech_type) {
break;
}
return (CRYPTO_SUCCESS);
}
/* ARGSUSED */
static int
{
int rv;
return (rv);
ctx_template, req);
return (rv);
}
/* ARGSUSED */
static int
{
int rv;
CKO_PUBLIC_KEY)) != CRYPTO_SUCCESS)
return (rv);
ctx_template, req);
return (rv);
}
static int
{
if (mech_type != ECDSA_SHA1_MECH_INFO_TYPE)
return (CRYPTO_MECHANISM_INVALID);
/* Don't digest if only returning length of signature. */
if (mech_type == ECDSA_SHA1_MECH_INFO_TYPE) {
digest, (void (*)())SHA1Update,
if (rv != CRYPTO_SUCCESS)
return (rv);
}
}
if (flag & CRYPTO_DO_SIGN) {
req);
} else
req);
return (rv);
}
/*
* This is a single-part signing routine. It does not
* compute a hash before signing.
*/
static int
{
int kmflag;
¶m_len)) != CRYPTO_SUCCESS) {
return (rv);
}
return (CRYPTO_DATA_LEN_RANGE);
!= CRYPTO_SUCCESS) {
return (rv);
}
/* structure assignment */
&private_len)) != CRYPTO_SUCCESS) {
return (rv);
}
kmflag)) != SECSuccess) {
if (ss == SECBufferTooSmall)
return (CRYPTO_BUFFER_TOO_SMALL);
return (CRYPTO_FAILED);
}
if (rv == CRYPTO_SUCCESS) {
/* copy out the signature */
return (rv);
}
return (rv);
}
/* ARGSUSED */
static int
{
int rv;
break;
default:
break;
}
if (rv != CRYPTO_BUFFER_TOO_SMALL)
return (rv);
}
/* ARGSUSED */
static int
{
int rv;
if (mech_type == ECDSA_MECH_INFO_TYPE) {
return (CRYPTO_MECHANISM_INVALID);
}
if (mech_type == ECDSA_SHA1_MECH_INFO_TYPE)
(void (*)())SHA1Update, (void (*)())SHA1Final,
if (rv != CRYPTO_SUCCESS)
return (rv);
}
/* ARGSUSED */
static int
{
int rv;
if (rv != CRYPTO_BUFFER_TOO_SMALL)
return (rv);
}
/* ARGSUSED */
static int
{
int rv;
int kmflag;
return (rv);
¶ms_len)) {
return (CRYPTO_ARGUMENTS_BAD);
}
/* ASN1 check */
if (params[0] != 0x06 ||
return (CRYPTO_ATTRIBUTE_VALUE_INVALID);
}
/* bad curve OID */
return (CRYPTO_ARGUMENTS_BAD);
}
/* structure assignment */
} else {
/* structure assignment */
}
return (rv);
}
static int
{
int kmflag;
¶m_len)) != CRYPTO_SUCCESS) {
return (rv);
}
return (CRYPTO_SIGNATURE_LEN_RANGE);
}
signed_data)) != CRYPTO_SUCCESS) {
return (rv);
}
return (CRYPTO_DATA_LEN_RANGE);
!= CRYPTO_SUCCESS) {
return (rv);
}
/* structure assignment */
&public_len)) != CRYPTO_SUCCESS) {
return (rv);
}
!= SECSuccess) {
} else {
rv = CRYPTO_SUCCESS;
}
return (rv);
}
/* ARGSUSED */
static int
{
int rv;
break;
default:
break;
}
return (rv);
}
/* ARGSUSED */
static int
{
int rv;
(void (*)())SHA1Update, (void (*)())SHA1Final,
break;
default:
}
if (rv != CRYPTO_SUCCESS)
return (rv);
}
/* ARGSUSED */
static int
{
int rv;
return (rv);
}
/* ARGSUSED */
static int
{
int rv;
int kmflag;
CKO_PUBLIC_KEY)) != CRYPTO_SUCCESS)
return (rv);
¶ms_len)) {
return (CRYPTO_ARGUMENTS_BAD);
}
/* ASN1 check */
if (params[0] != 0x06 ||
return (CRYPTO_ATTRIBUTE_VALUE_INVALID);
}
/* bad curve OID */
return (CRYPTO_ARGUMENTS_BAD);
}
/* structure assignment */
} else {
/* structure assignment */
}
return (rv);
}
/* ARGSUSED */
static int
{
unsigned params_len;
int valuelen;
int pointlen;
int xylen;
int kmflag;
return (CRYPTO_MECHANISM_INVALID);
}
/* optional */
(void) get_template_attr_ulong(pub_template,
/* optional */
(void) get_template_attr_ulong(pri_template,
/* optional */
(void) get_template_attr_ulong(pub_template,
/* optional */
(void) get_template_attr_ulong(pri_template,
return (CRYPTO_TEMPLATE_INCONSISTENT);
}
return (CRYPTO_TEMPLATE_INCONSISTENT);
}
return (CRYPTO_TEMPLATE_INCONSISTENT);
}
return (CRYPTO_TEMPLATE_INCONSISTENT);
}
/* public output template must contain CKA_EC_POINT attribute */
CKA_EC_POINT)) == -1) {
return (CRYPTO_TEMPLATE_INCOMPLETE);
}
/* private output template must contain CKA_VALUE attribute */
CKA_VALUE)) == -1) {
return (CRYPTO_TEMPLATE_INCOMPLETE);
}
CKA_EC_PARAMS)) == -1) {
return (CRYPTO_TEMPLATE_INCOMPLETE);
}
/* ASN1 check */
if (params[0] != 0x06 ||
return (CRYPTO_ATTRIBUTE_VALUE_INVALID);
}
/* bad curve OID */
return (CRYPTO_ARGUMENTS_BAD);
}
return (CRYPTO_FAILED);
}
/* ASSERT that xylen - 1 is divisible by 2 */
goto out;
}
goto out;
}
out:
return (rv);
}
/* ARGSUSED */
static int
{
int kmflag;
return (CRYPTO_MECHANISM_INVALID);
}
/* LINTED: pointer alignment */
return (CRYPTO_MECHANISM_PARAM_INVALID);
}
return (CRYPTO_ARGUMENTS_BAD);
}
return (rv);
}
switch (key_type) {
case CKK_DES:
break;
case CKK_DES2:
break;
case CKK_DES3:
break;
case CKK_RC4:
case CKK_AES:
case CKK_GENERIC_SECRET:
return (rv);
}
break;
default:
key_len = 0;
}
CKA_VALUE)) == -1) {
return (CRYPTO_TEMPLATE_INCOMPLETE);
}
CKA_EC_PARAMS)) == -1) {
return (CRYPTO_TEMPLATE_INCOMPLETE);
}
/* ASN1 check */
return (CRYPTO_ATTRIBUTE_VALUE_INVALID);
}
/* bad curve OID */
return (CRYPTO_ARGUMENTS_BAD);
}
CKA_VALUE)) == -1) {
goto out;
}
secret_item.len = 0;
return (CRYPTO_FAILED);
} else {
rv = CRYPTO_SUCCESS;
}
if (key_len == 0)
goto out;
}
goto out;
}
out:
return (rv);
}
static void
{
if (freeit)
}
static void
{
}