/*
* 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) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
*/
#include <modes/modes.h>
#include <sys/crypto/common.h>
#include <sys/crypto/spi.h>
#include <cryptoutil.h>
#include <syslog.h>
#define _AES_FIPS_POST
#define _RSA_FIPS_POST
#include <aes/aes_impl.h>
#include <rsa/rsa_impl.h>
#include <padding/padding.h>
#include "libsoftcrypto.h"
/*
* IMPORTANT: Each feature enhancement must be accompanied by an increment
* in the version.
*/
#define UCRYPTO_VERSION 4
typedef enum ucrypto_op {
UCRYPTO_NOOP = 0,
UCRYPTO_ENCRYPT,
UCRYPTO_DECRYPT,
UCRYPTO_SIGN,
UCRYPTO_VERIFY
} ucrypto_op_t;
typedef struct ucrypto_ctx {
ucrypto_mech_t mech;
uint8_t blocksize; /* for padding, blocksize multiple */
uint8_t remain; /* for padding, remainder % blocksize */
} ucrypto_ctx_t;
static int ucrypto_common_init(crypto_ctx_t *context, ucrypto_mech_t mech_type,
uchar_t *key_str, size_t key_len, void *iv, size_t iv_len,
ucrypto_op_t op_type);
static int ucrypto_common_update(crypto_ctx_t *context, uchar_t *in,
size_t in_len, uchar_t *out, size_t *out_len, ucrypto_op_t op_type);
static int ucrypto_common_final(crypto_ctx_t *context, uchar_t *out,
size_t *out_len, ucrypto_op_t op_type);
static int ucrypto_atomic(ucrypto_mech_t mech_type, uchar_t *key_str,
size_t key_len, void *iv, size_t iv_len, uchar_t *in, size_t in_len,
uchar_t *out, size_t *out_len, ucrypto_op_t op_type);
static int create_context(crypto_ctx_t *context, crypto_key_t key,
crypto_mechanism_t mech, ucrypto_op_t op_type);
static void free_context(crypto_ctx_t *context);
static int set_key(crypto_key_t *key, void *key_data, size_t key_len,
ucrypto_mech_t mech_type);
static int set_mechanism(crypto_mechanism_t *mech, ucrypto_mech_t mech_type,
void *iv, size_t iv_len);
#pragma init(ucrypto_init)
static void ucrypto_init();
#pragma inline(create_context)
static int
create_context(crypto_ctx_t *context, crypto_key_t key, crypto_mechanism_t mech,
ucrypto_op_t op_type)
{
int rv;
ucrypto_ctx_t *uctx = NULL;
int blocksize;
switch (mech.cm_type) {
case CRYPTO_AES_CBC_PAD:
blocksize = AES_BLOCK_LEN; /* i.e., padding needed */
mech.cm_type = CRYPTO_AES_CBC; /* remapped */
break;
default:
blocksize = 0; /* i.e., no padding needed */
break;
}
switch (mech.cm_type) {
case CRYPTO_AES_ECB:
case CRYPTO_AES_CBC:
case CRYPTO_AES_CTR:
case CRYPTO_AES_CCM:
case CRYPTO_AES_GCM:
case CRYPTO_AES_CFB128:
case CRYPTO_AES_XTS:
/* UCRYPTO_SIGN and UCRYPTO_VERIFY ops are invalid here */
if (op_type == UCRYPTO_SIGN || op_type == UCRYPTO_VERIFY) {
rv = CRYPTO_MECH_NOT_SUPPORTED;
break;
}
context->cc_flags |= CRYPTO_PROVIDER_PRIVATE_HAS_FUNCS;
rv = aes_common_init(context, &mech, &key, NULL, NULL,
(op_type == UCRYPTO_ENCRYPT) ? B_TRUE : B_FALSE);
break;
case CRYPTO_RSA_PKCS:
case CRYPTO_RSA_X_509:
case CRYPTO_MD5_RSA_PKCS:
case CRYPTO_SHA1_RSA_PKCS:
case CRYPTO_SHA224_RSA_PKCS:
case CRYPTO_SHA256_RSA_PKCS:
case CRYPTO_SHA384_RSA_PKCS:
case CRYPTO_SHA512_RSA_PKCS:
/* UCRYPTO_ENCRYPT and UCRYPTO_DECRYPT ops are invalid here */
if (op_type == UCRYPTO_ENCRYPT || op_type == UCRYPTO_DECRYPT) {
rv = CRYPTO_MECH_NOT_SUPPORTED;
break;
}
rv = rsaprov_sign_verify_common_init(context, &mech, &key,
NULL, NULL);
break;
default:
rv = CRYPTO_MECH_NOT_SUPPORTED;
}
if (rv != CRYPTO_SUCCESS)
return (rv);
/* Create framework context */
uctx = malloc(sizeof (ucrypto_ctx_t));
if (uctx == NULL)
return (CRYPTO_HOST_MEMORY);
uctx->mech = mech.cm_type;
uctx->blocksize = blocksize; /* constant based on mech type */
uctx->remain = 0; /* continuously updated with input */
context->cc_framework_private = uctx;
return (CRYPTO_SUCCESS);
}
/*
* This function frees the context for ucrypto, not for the provider
* the module code handles that.
*/
#pragma inline(free_context)
static void
free_context(crypto_ctx_t *context)
{
ucrypto_ctx_t *uctx = (ucrypto_ctx_t *)(context->cc_framework_private);
if (uctx != NULL)
free(uctx);
context->cc_framework_private = NULL;
}
#pragma inline(set_key)
static int
set_key(crypto_key_t *key, void *key_data, size_t key_len,
ucrypto_mech_t mech_type)
{
switch (mech_type) {
case CRYPTO_AES_ECB:
case CRYPTO_AES_CBC:
case CRYPTO_AES_CBC_PAD:
case CRYPTO_AES_CTR:
case CRYPTO_AES_CCM:
case CRYPTO_AES_GCM:
case CRYPTO_AES_CFB128:
case CRYPTO_AES_XTS:
case CRYPTO_AES_XCBC_MAC:
key->ck_format = CRYPTO_KEY_RAW;
key->ck_data = key_data;
key->ck_length = CRYPTO_BYTES2BITS(key_len);
break;
case CRYPTO_RSA_PKCS:
case CRYPTO_RSA_X_509:
case CRYPTO_MD5_RSA_PKCS:
case CRYPTO_SHA1_RSA_PKCS:
case CRYPTO_SHA224_RSA_PKCS:
case CRYPTO_SHA256_RSA_PKCS:
case CRYPTO_SHA384_RSA_PKCS:
case CRYPTO_SHA512_RSA_PKCS:
key->ck_format = CRYPTO_KEY_ATTR_LIST;
key->ck_attrs = (crypto_object_attribute_t *)key_data;
key->ck_count = key_len;
break;
default:
return (CRYPTO_MECH_NOT_SUPPORTED);
}
return (CRYPTO_SUCCESS);
}
/*
* If the mechanism is defined in this function, then it is supported.
* If it is supported, sets up the initialization vector in crypto_mechanism_t.
*/
#pragma inline(set_mechanism)
static int
set_mechanism(crypto_mechanism_t *mech, ucrypto_mech_t mech_type,
void *iv, size_t iv_len)
{
if (mech_type == CRYPTO_AES_ECB && iv_len != 0)
return (CRYPTO_MECHANISM_PARAM_INVALID);
mech->cm_type = mech_type;
mech->cm_param = (char *)iv;
mech->cm_param_len = iv_len;
return (CRYPTO_SUCCESS);
}
/* Return the version of this library */
int
ucrypto_version(void)
{
return (UCRYPTO_VERSION);
}
/*
* UCRYPTO common internal functions.
*/
#pragma inline(ucrypto_common_init)
static int
ucrypto_common_init(crypto_ctx_t *context, ucrypto_mech_t mech_type,
uchar_t *key_str, size_t key_len, void *iv, size_t iv_len,
ucrypto_op_t op_type)
{
int rv;
crypto_key_t key = { 0 };
crypto_mechanism_t mech = { 0 };
rv = set_mechanism(&mech, mech_type, iv, iv_len);
if (rv != CRYPTO_SUCCESS)
return (rv);
rv = set_key(&key, key_str, key_len, mech_type);
if (rv != CRYPTO_SUCCESS)
return (rv);
rv = create_context(context, key, mech, op_type);
if (rv != CRYPTO_SUCCESS)
return (rv);
return (CRYPTO_SUCCESS);
}
#pragma inline(ucrypto_common_update)
static int
ucrypto_common_update(crypto_ctx_t *context, uchar_t *in, size_t in_len,
uchar_t *out, size_t *out_len, ucrypto_op_t op_type)
{
int rv;
crypto_data_t idata = { 0 };
crypto_data_t odata = { 0 };
ucrypto_ctx_t *uctx = (ucrypto_ctx_t *)(context->cc_framework_private);
CRYPTO_SET_RAW_DATA(idata, in, in_len);
switch (uctx->mech) {
case CRYPTO_AES_ECB:
case CRYPTO_AES_CBC:
case CRYPTO_AES_CTR:
case CRYPTO_AES_CCM:
case CRYPTO_AES_GCM:
case CRYPTO_AES_CFB128:
case CRYPTO_AES_XTS:
if (out_len == NULL) {
rv = CRYPTO_ARGUMENTS_BAD;
goto cleanup;
}
CRYPTO_SET_RAW_DATA(odata, out, *out_len);
if (op_type == UCRYPTO_ENCRYPT)
rv = aes_encrypt_update(context, &idata, &odata, NULL);
else if (op_type == UCRYPTO_DECRYPT)
rv = aes_decrypt_update(context, &idata, &odata, NULL);
else
rv = CRYPTO_MECH_NOT_SUPPORTED;
if (rv != CRYPTO_SUCCESS)
goto cleanup;
*out_len = odata.cd_length;
break;
case CRYPTO_RSA_PKCS:
case CRYPTO_RSA_X_509:
case CRYPTO_MD5_RSA_PKCS:
case CRYPTO_SHA1_RSA_PKCS:
case CRYPTO_SHA224_RSA_PKCS:
case CRYPTO_SHA256_RSA_PKCS:
case CRYPTO_SHA384_RSA_PKCS:
case CRYPTO_SHA512_RSA_PKCS:
if (op_type == UCRYPTO_SIGN)
rv = rsaprov_sign_update(context, &idata, NULL);
else if (op_type == UCRYPTO_VERIFY)
rv = rsaprov_verify_update(context, &idata, NULL);
else
rv = CRYPTO_MECH_NOT_SUPPORTED;
if (rv != CRYPTO_SUCCESS)
goto cleanup;
break;
default:
rv = CRYPTO_MECH_NOT_SUPPORTED;
goto cleanup;
}
/* Reset remainder bytes for padded mechs only if update successful. */
if (uctx->blocksize != 0)
uctx->remain = ((uctx->remain + in_len) % uctx->blocksize);
return (CRYPTO_SUCCESS);
cleanup:
free_context(context);
return (rv);
}
#pragma inline(ucrypto_common_final)
static int
ucrypto_common_final(crypto_ctx_t *context, uchar_t *out, size_t *out_len,
ucrypto_op_t op_type)
{
int rv;
crypto_data_t odata = { 0 };
ucrypto_ctx_t *uctx = (ucrypto_ctx_t *)(context->cc_framework_private);
if (out_len == NULL) {
rv = CRYPTO_ARGUMENTS_BAD;
goto cleanup;
}
CRYPTO_SET_RAW_DATA(odata, out, *out_len);
switch (uctx->mech) {
case CRYPTO_AES_ECB:
case CRYPTO_AES_CBC:
case CRYPTO_AES_CTR:
case CRYPTO_AES_CCM:
case CRYPTO_AES_GCM:
case CRYPTO_AES_CFB128:
case CRYPTO_AES_XTS:
/*
* If this is a padded mech, do one more update op on the
* padding buffer instead of the final op; the padding will
* guarantee no more residual data, so the final op becomes
* unnecessary.
*/
if (op_type == UCRYPTO_ENCRYPT && uctx->blocksize != 0) {
crypto_data_t idata = { 0 };
uint8_t padded[AES_BLOCK_LEN]; /* longest blocksize */
size_t extra = uctx->blocksize - uctx->remain;
(void) pkcs7_encode(NULL, uctx->remain, padded, extra,
uctx->blocksize);
CRYPTO_SET_RAW_DATA(idata, padded, extra);
/*
* Remember, mechs were remapped to their unpadded
* counterparts; blocksize != 0 means padded mech.
*/
switch (uctx->mech) {
case CRYPTO_AES_CBC:
rv = aes_encrypt_update(context, &idata,
&odata, NULL);
break;
default:
rv = CRYPTO_MECH_NOT_SUPPORTED;
break;
}
if (rv != CRYPTO_SUCCESS)
goto cleanup;
} else if (op_type == UCRYPTO_DECRYPT && uctx->blocksize != 0) {
if (uctx->remain != 0) {
rv = CRYPTO_ENCRYPTED_DATA_INVALID;
goto cleanup;
}
}
if (op_type == UCRYPTO_ENCRYPT)
rv = aes_encrypt_final(context, &odata, NULL);
else if (op_type == UCRYPTO_DECRYPT)
rv = aes_decrypt_final(context, &odata, NULL);
else
rv = CRYPTO_MECH_NOT_SUPPORTED;
if (rv != CRYPTO_SUCCESS)
goto cleanup;
if (op_type == UCRYPTO_DECRYPT && uctx->blocksize != 0) {
if (pkcs7_decode(out, &(odata.cd_length)) != 0) {
rv = CRYPTO_ENCRYPTED_DATA_INVALID;
goto cleanup;
}
}
break;
case CRYPTO_RSA_PKCS:
case CRYPTO_RSA_X_509:
case CRYPTO_MD5_RSA_PKCS:
case CRYPTO_SHA1_RSA_PKCS:
case CRYPTO_SHA224_RSA_PKCS:
case CRYPTO_SHA256_RSA_PKCS:
case CRYPTO_SHA384_RSA_PKCS:
case CRYPTO_SHA512_RSA_PKCS:
if (op_type == UCRYPTO_SIGN)
rv = rsaprov_sign_final(context, &odata, NULL);
else if (op_type == UCRYPTO_VERIFY)
rv = rsaprov_verify_final(context, &odata, NULL);
else
rv = CRYPTO_MECH_NOT_SUPPORTED;
if (rv != CRYPTO_SUCCESS)
goto cleanup;
break;
default:
rv = CRYPTO_MECH_NOT_SUPPORTED;
goto cleanup;
}
*out_len = odata.cd_length;
cleanup:
free_context(context);
return (rv);
}
#pragma inline(ucrypto_atomic)
static int
ucrypto_atomic(ucrypto_mech_t mech_type, uchar_t *key_str, size_t key_len,
void *iv, size_t iv_len, uchar_t *in, size_t in_len,
uchar_t *out, size_t *out_len, ucrypto_op_t op_type)
{
int rv;
crypto_mechanism_t mech = { 0 };
crypto_data_t idata = { 0 };
crypto_data_t odata = { 0 };
crypto_key_t key = { 0 };
uchar_t *padded = NULL;
size_t padded_len;
size_t extra;
if (out_len == NULL)
return (CRYPTO_ARGUMENTS_BAD);
switch (mech_type) {
case CRYPTO_AES_CBC_PAD:
if (op_type == UCRYPTO_ENCRYPT) {
extra = AES_BLOCK_LEN - (in_len % AES_BLOCK_LEN);
if (*out_len - in_len < extra)
return (CRYPTO_BUFFER_TOO_SMALL);
/*
* Copy data to allocated buffer big enough to hold
* it plus extra padding.
*/
padded_len = in_len + extra;
padded = malloc(padded_len);
if (padded == NULL)
return (CRYPTO_HOST_MEMORY);
(void) pkcs7_encode(in, in_len, padded, padded_len,
AES_BLOCK_LEN);
mech_type = CRYPTO_AES_CBC;
} else if (op_type == UCRYPTO_DECRYPT) {
/*
* Copy data to temporary allocated buffer.
*/
padded_len = *out_len;
padded = malloc(padded_len);
if (padded == NULL)
return (CRYPTO_HOST_MEMORY);
bzero(padded, padded_len); /* out could be NULL */
(void) memcpy(padded, out, *out_len);
mech_type = CRYPTO_AES_CBC;
} else
return (CRYPTO_MECH_NOT_SUPPORTED);
break;
default:
break;
}
rv = set_mechanism(&mech, mech_type, iv, iv_len);
if (rv != CRYPTO_SUCCESS)
goto out_atomic;
rv = set_key(&key, key_str, key_len, mech_type);
if (rv != CRYPTO_SUCCESS)
goto out_atomic;
if (op_type == UCRYPTO_ENCRYPT && padded != NULL) {
CRYPTO_SET_RAW_DATA(idata, padded, padded_len);
} else {
CRYPTO_SET_RAW_DATA(idata, in, in_len);
}
if (op_type == UCRYPTO_DECRYPT && padded != NULL) {
CRYPTO_SET_RAW_DATA(odata, padded, padded_len);
} else {
CRYPTO_SET_RAW_DATA(odata, out, *out_len);
}
switch (mech_type) {
case CRYPTO_AES_ECB:
case CRYPTO_AES_CBC:
case CRYPTO_AES_CTR:
case CRYPTO_AES_CCM:
case CRYPTO_AES_GCM:
case CRYPTO_AES_CFB128:
case CRYPTO_AES_XTS:
case CRYPTO_AES_XCBC_MAC:
if (op_type == UCRYPTO_ENCRYPT)
rv = aes_encrypt_atomic(NULL, NULL, &mech, &key,
&idata, &odata, NULL, NULL);
else if (op_type == UCRYPTO_DECRYPT)
rv = aes_decrypt_atomic(NULL, NULL, &mech, &key,
&idata, &odata, NULL, NULL);
else
rv = CRYPTO_MECH_NOT_SUPPORTED;
break;
case CRYPTO_RSA_PKCS:
case CRYPTO_RSA_X_509:
case CRYPTO_MD5_RSA_PKCS:
case CRYPTO_SHA1_RSA_PKCS:
case CRYPTO_SHA224_RSA_PKCS:
case CRYPTO_SHA256_RSA_PKCS:
case CRYPTO_SHA384_RSA_PKCS:
case CRYPTO_SHA512_RSA_PKCS:
if (op_type == UCRYPTO_ENCRYPT)
rv = rsaprov_encrypt_atomic(NULL, NULL, &mech,
&key, &idata, &odata, NULL, NULL);
else if (op_type == UCRYPTO_DECRYPT)
rv = rsaprov_decrypt_atomic(NULL, NULL, &mech,
&key, &idata, &odata, NULL, NULL);
else if (op_type == UCRYPTO_SIGN)
rv = rsaprov_sign_atomic(NULL, NULL, &mech,
&key, &idata, &odata, NULL, NULL);
else if (op_type == UCRYPTO_VERIFY)
rv = rsaprov_verify_atomic(NULL, NULL, &mech,
&key, &idata, &odata, NULL, NULL);
else
rv = CRYPTO_MECH_NOT_SUPPORTED;
break;
default:
rv = CRYPTO_MECH_NOT_SUPPORTED;
break;
}
if (op_type == UCRYPTO_DECRYPT && padded != NULL) {
if (pkcs7_decode(padded, &padded_len) != 0) {
rv = CRYPTO_ENCRYPTED_DATA_INVALID;
goto out_atomic;
}
odata.cd_length = padded_len;
if (out != NULL)
(void) memcpy(out, padded, padded_len);
}
*out_len = odata.cd_length;
out_atomic:
if (padded != NULL)
free(padded);
return (rv);
}
/*
* UCRYPTO exported functions.
*/
/* Encrypt API */
int
ucrypto_encrypt_init(crypto_ctx_t *context, ucrypto_mech_t mech_type,
uchar_t *key_str, size_t key_len, void *iv, size_t iv_len)
{
return (ucrypto_common_init(context, mech_type, key_str, key_len,
iv, iv_len, UCRYPTO_ENCRYPT));
}
int
ucrypto_encrypt_update(crypto_ctx_t *context, uchar_t *in, size_t in_len,
uchar_t *out, size_t *out_len)
{
rawdata_crypt_update_function_t *update_func;
if (context->cc_flags & CRYPTO_PROVIDER_PRIVATE_HAS_FUNCS) {
update_func =
((rawdata_funcs_and_ctx_t *)
(context->cc_provider_private))->crypt_funcs.encrypt_update;
if (update_func != NULL) {
return (update_func(context, in, in_len, out, out_len));
} else {
context->cc_flags &= ~CRYPTO_PROVIDER_PRIVATE_HAS_FUNCS;
context->cc_provider_private =
((rawdata_funcs_and_ctx_t *)
(context->cc_provider_private))->ctx;
}
}
return (ucrypto_common_update(context, in, in_len, out, out_len,
UCRYPTO_ENCRYPT));
}
int
ucrypto_encrypt_final(crypto_ctx_t *context, uchar_t *out, size_t *out_len)
{
return (ucrypto_common_final(context, out, out_len, UCRYPTO_ENCRYPT));
}
#define GET_RAWDATA_FUNCS(mech_type) \
switch (mech_type) { \
case CRYPTO_AES_CBC: \
case CRYPTO_AES_ECB: \
case CRYPTO_AES_CFB128: \
case CRYPTO_AES_CTR: \
funcs = rawdata_get_aes_funcs(mech_type); \
break; \
default: \
funcs = NULL; \
break; \
}
int
ucrypto_encrypt(ucrypto_mech_t mech_type, uchar_t *key_str, size_t key_len,
void *iv, size_t iv_len, uchar_t *in, size_t in_len,
uchar_t *out, size_t *out_len)
{
rawdata_crypt_functions_t *funcs;
GET_RAWDATA_FUNCS(mech_type);
if (funcs) {
rawdata_crypt_function_t *encr_func;
encr_func = funcs->encrypt;
if (encr_func != NULL) {
return (encr_func(key_str, key_len, iv, iv_len,
in, in_len, out, out_len));
}
}
return (ucrypto_atomic(mech_type, key_str, key_len, iv, iv_len, in,
in_len, out, out_len, UCRYPTO_ENCRYPT));
}
/* Decrypt API */
int
ucrypto_decrypt_init(crypto_ctx_t *context, ucrypto_mech_t mech_type,
uchar_t *key_str, size_t key_len, void *iv, size_t iv_len)
{
return (ucrypto_common_init(context, mech_type, key_str, key_len,
iv, iv_len, UCRYPTO_DECRYPT));
}
int
ucrypto_decrypt_update(crypto_ctx_t *context, uchar_t *in, size_t in_len,
uchar_t *out, size_t *out_len)
{
rawdata_crypt_update_function_t *update_func;
if (context->cc_flags & CRYPTO_PROVIDER_PRIVATE_HAS_FUNCS) {
update_func =
((rawdata_funcs_and_ctx_t *)
(context->cc_provider_private))->crypt_funcs.decrypt_update;
if (update_func != NULL) {
return (update_func(context, in, in_len, out, out_len));
} else {
context->cc_flags &= ~CRYPTO_PROVIDER_PRIVATE_HAS_FUNCS;
context->cc_provider_private =
((rawdata_funcs_and_ctx_t *)
(context->cc_provider_private))->ctx;
}
}
return (ucrypto_common_update(context, in, in_len, out, out_len,
UCRYPTO_DECRYPT));
}
int
ucrypto_decrypt_final(crypto_ctx_t *context, uchar_t *out, size_t *out_len)
{
return (ucrypto_common_final(context, out, out_len, UCRYPTO_DECRYPT));
}
int
ucrypto_decrypt(ucrypto_mech_t mech_type, uchar_t *key_str, size_t key_len,
void *iv, size_t iv_len, uchar_t *in, size_t in_len,
uchar_t *out, size_t *out_len)
{
rawdata_crypt_functions_t *funcs;
GET_RAWDATA_FUNCS(mech_type);
if (funcs) {
rawdata_crypt_function_t *decr_func;
decr_func = funcs->decrypt;
if (decr_func != NULL) {
return (decr_func(key_str, key_len, iv, iv_len,
in, in_len, out, out_len));
}
}
return (ucrypto_atomic(mech_type, key_str, key_len, iv, iv_len, in,
in_len, out, out_len, UCRYPTO_DECRYPT));
}
/* Sign API */
int
ucrypto_sign_init(crypto_ctx_t *context, ucrypto_mech_t mech_type,
uchar_t *key_str, size_t key_len, void *iv, size_t iv_len)
{
return (ucrypto_common_init(context, mech_type, key_str, key_len,
iv, iv_len, UCRYPTO_SIGN));
}
int
ucrypto_sign_update(crypto_ctx_t *context, uchar_t *data_str, size_t data_len)
{
return (ucrypto_common_update(context, data_str, data_len,
NULL, NULL, UCRYPTO_SIGN));
}
int
ucrypto_sign_final(crypto_ctx_t *context, uchar_t *sig_str, size_t *sig_len)
{
return (ucrypto_common_final(context, sig_str, sig_len,
UCRYPTO_SIGN));
}
int
ucrypto_sign(ucrypto_mech_t mech_type, uchar_t *key_str, size_t key_len,
void *iv, size_t iv_len, uchar_t *data_str, size_t data_len,
uchar_t *sig_str, size_t *sig_len)
{
return (ucrypto_atomic(mech_type, key_str, key_len, iv, iv_len,
data_str, data_len, sig_str, sig_len, UCRYPTO_SIGN));
}
/* Verify API */
int
ucrypto_verify_init(crypto_ctx_t *context, ucrypto_mech_t mech_type,
uchar_t *key_str, size_t key_len, void *iv, size_t iv_len)
{
return (ucrypto_common_init(context, mech_type, key_str, key_len,
iv, iv_len, UCRYPTO_VERIFY));
}
int
ucrypto_verify_update(crypto_ctx_t *context, uchar_t *data_str, size_t data_len)
{
return (ucrypto_common_update(context, data_str, data_len,
NULL, NULL, UCRYPTO_VERIFY));
}
int
ucrypto_verify_final(crypto_ctx_t *context, uchar_t *sig_str, size_t *sig_len)
{
return (ucrypto_common_final(context, sig_str, sig_len,
UCRYPTO_VERIFY));
}
int
ucrypto_verify(ucrypto_mech_t mech_type, uchar_t *key_str, size_t key_len,
void *iv, size_t iv_len, uchar_t *data_str, size_t data_len,
uchar_t *sig_str, size_t *sig_len)
{
return (ucrypto_atomic(mech_type, key_str, key_len, iv, iv_len,
data_str, data_len, sig_str, sig_len, UCRYPTO_VERIFY));
}
static void
ucrypto_init()
{
int ucrypto_fips_mode = CRYPTO_FIPS_MODE_DISABLED;
int rv;
/*
* Perform POST when fips mode is enabled.
*/
(void) get_fips_mode(&ucrypto_fips_mode);
if (ucrypto_fips_mode == CRYPTO_FIPS_MODE_ENABLED) {
/* AES Power-On SelfTest for 128-bit key. */
if ((rv = fips_aes_post(FIPS_AES_128_KEY_SIZE)) != 0) {
syslog(LOG_ERR, "ucrypto_init: FIPS-140 Power On Self "
"Test (AES-128) failed, rv= %d", rv);
abort();
}
/* AES Power-On SelfTest for 192-bit key. */
if ((rv = fips_aes_post(FIPS_AES_192_KEY_SIZE)) != 0) {
syslog(LOG_ERR, "ucrypto_init: FIPS-140 Power On Self "
"Test (AES-192) failed, rv= %d", rv);
abort();
}
/* AES Power-On SelfTest for 256-bit key. */
if ((rv = fips_aes_post(FIPS_AES_256_KEY_SIZE)) != 0) {
syslog(LOG_ERR, "ucrypto_init: FIPS-140 Power On Self "
"Test (AES-256) failed, rv= %d", rv);
abort();
}
/*
* RSA Power-On SelfTest
*/
if ((rv = fips_rsa_post()) != 0) {
syslog(LOG_ERR, "ucrypto_init: FIPS-140 Power On Self "
"Test (RSA) failed, rv= %d", rv);
abort();
}
}
}