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 2007 Sun Microsystems, Inc. All rights reserved.
2N/A * Use is subject to license terms.
2N/A */
2N/A
2N/A#pragma ident "%Z%%M% %I% %E% SMI"
2N/A
2N/A#include <pthread.h>
2N/A#include <errno.h>
2N/A#include <stdio.h>
2N/A#include <strings.h>
2N/A#include <sys/crypto/ioctl.h>
2N/A#include <security/cryptoki.h>
2N/A#include <security/pkcs11t.h>
2N/A#include "softSession.h"
2N/A#include "softObject.h"
2N/A#include "softOps.h"
2N/A#include "softMAC.h"
2N/A#include "kernelSoftCommon.h"
2N/A
2N/A/*
2N/A * Do the operation(s) specified by opflag.
2N/A */
2N/ACK_RV
2N/Ado_soft_digest(void **s, CK_MECHANISM_PTR pMechanism, CK_BYTE_PTR pData,
2N/A CK_ULONG ulDataLen, CK_BYTE_PTR pDigest, CK_ULONG_PTR pulDigestLen,
2N/A int opflag)
2N/A{
2N/A soft_session_t *session_p;
2N/A CK_RV rv = CKR_ARGUMENTS_BAD;
2N/A
2N/A session_p = *((soft_session_t **)s);
2N/A if (session_p == NULL) {
2N/A if (!(opflag & OP_INIT)) {
2N/A return (CKR_ARGUMENTS_BAD);
2N/A }
2N/A
2N/A session_p = calloc(1, sizeof (soft_session_t));
2N/A /*
2N/A * Initialize the lock for the newly created session.
2N/A * We do only the minimum needed setup for the
2N/A * soft_digest* routines to succeed.
2N/A */
2N/A if (pthread_mutex_init(&session_p->session_mutex, NULL) != 0) {
2N/A free(session_p);
2N/A return (CKR_CANT_LOCK);
2N/A }
2N/A
2N/A *s = session_p;
2N/A } else if (opflag & OP_INIT) {
2N/A free_soft_ctx(session_p, OP_DIGEST);
2N/A }
2N/A
2N/A if (opflag & OP_INIT) {
2N/A rv = soft_digest_init(session_p, pMechanism);
2N/A if (rv != CKR_OK)
2N/A return (rv);
2N/A }
2N/A
2N/A if (opflag & OP_SINGLE) {
2N/A rv = soft_digest(session_p, pData, ulDataLen,
2N/A pDigest, pulDigestLen);
2N/A } else {
2N/A if (opflag & OP_UPDATE) {
2N/A rv = soft_digest_update(session_p, pData, ulDataLen);
2N/A if (rv != CKR_OK)
2N/A return (rv);
2N/A }
2N/A
2N/A if (opflag & OP_FINAL) {
2N/A rv = soft_digest_final(session_p,
2N/A pDigest, pulDigestLen);
2N/A }
2N/A }
2N/A
2N/A return (rv);
2N/A}
2N/A
2N/A/*
2N/A * opflag specifies whether this is a sign or verify.
2N/A */
2N/ACK_RV
2N/Ado_soft_hmac_init(void **s, CK_MECHANISM_PTR pMechanism,
2N/A CK_BYTE_PTR kval, CK_ULONG klen, int opflag)
2N/A{
2N/A CK_RV rv;
2N/A soft_object_t keyobj;
2N/A secret_key_obj_t skeyobj;
2N/A soft_object_t *key_p;
2N/A soft_session_t *session_p;
2N/A
2N/A session_p = *((soft_session_t **)s);
2N/A if (session_p == NULL) {
2N/A session_p = calloc(1, sizeof (soft_session_t));
2N/A /* See comments in do_soft_digest() above */
2N/A if (pthread_mutex_init(&session_p->session_mutex, NULL) != 0) {
2N/A free(session_p);
2N/A return (CKR_CANT_LOCK);
2N/A }
2N/A
2N/A *s = session_p;
2N/A } else if (opflag & OP_INIT) {
2N/A free_soft_ctx(session_p, opflag);
2N/A }
2N/A
2N/A /* Do the minimum needed setup for the call to succeed */
2N/A key_p = &keyobj;
2N/A bzero(key_p, sizeof (soft_object_t));
2N/A key_p->class = CKO_SECRET_KEY;
2N/A key_p->key_type = CKK_GENERIC_SECRET;
2N/A
2N/A bzero(&skeyobj, sizeof (secret_key_obj_t));
2N/A OBJ_SEC(key_p) = &skeyobj;
2N/A OBJ_SEC_VALUE(key_p) = kval;
2N/A OBJ_SEC_VALUE_LEN(key_p) = klen;
2N/A
2N/A rv = soft_hmac_sign_verify_init_common(session_p, pMechanism,
2N/A key_p, opflag & OP_SIGN);
2N/A
2N/A return (rv);
2N/A}
2N/A
2N/A/*
2N/A * opflag specifies whether this is a sign or verify.
2N/A */
2N/ACK_RV
2N/Ado_soft_hmac_update(void **s, CK_BYTE_PTR pData, CK_ULONG ulDataLen, int opflag)
2N/A{
2N/A soft_session_t *session_p;
2N/A
2N/A session_p = *((soft_session_t **)s);
2N/A if (session_p == NULL) {
2N/A return (CKR_ARGUMENTS_BAD);
2N/A }
2N/A
2N/A return (soft_hmac_sign_verify_update(session_p,
2N/A pData, ulDataLen, opflag & OP_SIGN));
2N/A}
2N/A
2N/A/*
2N/A * opflag specifies whether this is a final or single.
2N/A */
2N/ACK_RV
2N/Ado_soft_hmac_sign(void **s, CK_BYTE_PTR pData, CK_ULONG ulDataLen,
2N/A CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen, int opflag)
2N/A{
2N/A CK_RV rv;
2N/A soft_session_t *session_p;
2N/A CK_BYTE hmac[SHA512_DIGEST_LENGTH]; /* use the maximum size */
2N/A
2N/A session_p = *((soft_session_t **)s);
2N/A if (session_p == NULL || !(opflag & OP_SINGLE || opflag & OP_FINAL)) {
2N/A return (CKR_ARGUMENTS_BAD);
2N/A }
2N/A
2N/A rv = soft_hmac_sign_verify_common(session_p, pData, ulDataLen,
2N/A (pSignature != NULL ? hmac : NULL), pulSignatureLen, B_TRUE);
2N/A
2N/A if ((rv == CKR_OK) && (pSignature != NULL)) {
2N/A (void) memcpy(pSignature, hmac, *pulSignatureLen);
2N/A }
2N/A
2N/A return (rv);
2N/A}
2N/A
2N/A/*
2N/A * opflag specifies whether this is a final or single.
2N/A */
2N/ACK_RV
2N/Ado_soft_hmac_verify(void **s, CK_BYTE_PTR pData, CK_ULONG ulDataLen,
2N/A CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen, int opflag)
2N/A{
2N/A CK_RV rv;
2N/A CK_ULONG len;
2N/A soft_session_t *session_p;
2N/A soft_hmac_ctx_t *hmac_ctx;
2N/A CK_BYTE hmac[SHA512_DIGEST_LENGTH]; /* use the maximum size */
2N/A
2N/A session_p = *((soft_session_t **)s);
2N/A if (session_p == NULL || !(opflag & OP_SINGLE || opflag & OP_FINAL)) {
2N/A return (CKR_ARGUMENTS_BAD);
2N/A }
2N/A
2N/A hmac_ctx = (soft_hmac_ctx_t *)session_p->verify.context;
2N/A len = hmac_ctx->hmac_len;
2N/A
2N/A rv = soft_hmac_sign_verify_common(session_p, pData,
2N/A ulDataLen, hmac, &len, B_FALSE);
2N/A
2N/A if (rv == CKR_OK) {
2N/A if (len != ulSignatureLen) {
2N/A rv = CKR_SIGNATURE_LEN_RANGE;
2N/A }
2N/A
2N/A if (memcmp(hmac, pSignature, len) != 0) {
2N/A rv = CKR_SIGNATURE_INVALID;
2N/A }
2N/A }
2N/A
2N/A return (rv);
2N/A}
2N/A
2N/A/*
2N/A * Helper routine to handle the case when the ctx is abandoned.
2N/A */
2N/Avoid
2N/Afree_soft_ctx(void *s, int opflag)
2N/A{
2N/A soft_session_t *session_p;
2N/A
2N/A session_p = (soft_session_t *)s;
2N/A if (session_p == NULL)
2N/A return;
2N/A
2N/A if (opflag & OP_SIGN) {
2N/A if (session_p->sign.context == NULL)
2N/A return;
2N/A bzero(session_p->sign.context, sizeof (soft_hmac_ctx_t));
2N/A free(session_p->sign.context);
2N/A session_p->sign.context = NULL;
2N/A session_p->sign.flags = 0;
2N/A } else if (opflag & OP_VERIFY) {
2N/A if (session_p->verify.context == NULL)
2N/A return;
2N/A bzero(session_p->verify.context, sizeof (soft_hmac_ctx_t));
2N/A free(session_p->verify.context);
2N/A session_p->verify.context = NULL;
2N/A session_p->verify.flags = 0;
2N/A } else {
2N/A if (session_p->digest.context == NULL)
2N/A return;
2N/A free(session_p->digest.context);
2N/A session_p->digest.context = NULL;
2N/A session_p->digest.flags = 0;
2N/A }
2N/A}