14072Skrishna /*
24072Skrishna  * CDDL HEADER START
34072Skrishna  *
44072Skrishna  * The contents of this file are subject to the terms of the
54072Skrishna  * Common Development and Distribution License (the "License").
64072Skrishna  * You may not use this file except in compliance with the License.
74072Skrishna  *
84072Skrishna  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
94072Skrishna  * or http://www.opensolaris.org/os/licensing.
104072Skrishna  * See the License for the specific language governing permissions
114072Skrishna  * and limitations under the License.
124072Skrishna  *
134072Skrishna  * When distributing Covered Code, include this CDDL HEADER in each
144072Skrishna  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
154072Skrishna  * If applicable, add the following below this CDDL HEADER, with the
164072Skrishna  * fields enclosed by brackets "[]" replaced with your own identifying
174072Skrishna  * information: Portions Copyright [yyyy] [name of copyright owner]
184072Skrishna  *
194072Skrishna  * CDDL HEADER END
204072Skrishna  */
214072Skrishna 
224072Skrishna /*
234072Skrishna  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
244072Skrishna  * Use is subject to license terms.
254072Skrishna  */
264072Skrishna 
274072Skrishna #pragma ident	"%Z%%M%	%I%	%E% SMI"
284072Skrishna 
294072Skrishna #include <pthread.h>
304072Skrishna #include <errno.h>
314072Skrishna #include <stdio.h>
324072Skrishna #include <strings.h>
334072Skrishna #include <sys/crypto/ioctl.h>
344072Skrishna #include <security/cryptoki.h>
354072Skrishna #include <security/pkcs11t.h>
364072Skrishna #include "softSession.h"
374072Skrishna #include "softObject.h"
384072Skrishna #include "softOps.h"
394072Skrishna #include "softMAC.h"
404072Skrishna #include "kernelSoftCommon.h"
414072Skrishna 
424072Skrishna /*
43*5616Skrishna  * Do the operation(s) specified by opflag.
444072Skrishna  */
454072Skrishna CK_RV
do_soft_digest(void ** s,CK_MECHANISM_PTR pMechanism,CK_BYTE_PTR pData,CK_ULONG ulDataLen,CK_BYTE_PTR pDigest,CK_ULONG_PTR pulDigestLen,int opflag)464072Skrishna do_soft_digest(void **s, CK_MECHANISM_PTR pMechanism, CK_BYTE_PTR pData,
474072Skrishna     CK_ULONG ulDataLen, CK_BYTE_PTR pDigest, CK_ULONG_PTR pulDigestLen,
484072Skrishna     int opflag)
494072Skrishna {
504072Skrishna 	soft_session_t *session_p;
51*5616Skrishna 	CK_RV rv = CKR_ARGUMENTS_BAD;
524072Skrishna 
534072Skrishna 	session_p = *((soft_session_t **)s);
544072Skrishna 	if (session_p == NULL) {
554072Skrishna 		if (!(opflag & OP_INIT)) {
564072Skrishna 			return (CKR_ARGUMENTS_BAD);
574072Skrishna 		}
584072Skrishna 
594072Skrishna 		session_p = calloc(1, sizeof (soft_session_t));
604072Skrishna 		/*
614072Skrishna 		 * Initialize the lock for the newly created session.
624072Skrishna 		 * We do only the minimum needed setup for the
634072Skrishna 		 * soft_digest* routines to succeed.
644072Skrishna 		 */
654072Skrishna 		if (pthread_mutex_init(&session_p->session_mutex, NULL) != 0) {
664072Skrishna 			free(session_p);
674072Skrishna 			return (CKR_CANT_LOCK);
684072Skrishna 		}
694072Skrishna 
704072Skrishna 		*s = session_p;
714072Skrishna 	} else if (opflag & OP_INIT) {
724072Skrishna 		free_soft_ctx(session_p, OP_DIGEST);
734072Skrishna 	}
744072Skrishna 
75*5616Skrishna 	if (opflag & OP_INIT) {
764072Skrishna 		rv = soft_digest_init(session_p, pMechanism);
77*5616Skrishna 		if (rv != CKR_OK)
78*5616Skrishna 			return (rv);
79*5616Skrishna 	}
804072Skrishna 
81*5616Skrishna 	if (opflag & OP_SINGLE) {
824072Skrishna 		rv = soft_digest(session_p, pData, ulDataLen,
834072Skrishna 		    pDigest, pulDigestLen);
84*5616Skrishna 	} else {
85*5616Skrishna 		if (opflag & OP_UPDATE) {
86*5616Skrishna 			rv = soft_digest_update(session_p, pData, ulDataLen);
87*5616Skrishna 			if (rv != CKR_OK)
88*5616Skrishna 				return (rv);
89*5616Skrishna 		}
904072Skrishna 
91*5616Skrishna 		if (opflag & OP_FINAL) {
92*5616Skrishna 			rv = soft_digest_final(session_p,
93*5616Skrishna 			    pDigest, pulDigestLen);
94*5616Skrishna 		}
954072Skrishna 	}
964072Skrishna 
974072Skrishna 	return (rv);
984072Skrishna }
994072Skrishna 
1004072Skrishna /*
1014072Skrishna  * opflag specifies whether this is a sign or verify.
1024072Skrishna  */
1034072Skrishna CK_RV
do_soft_hmac_init(void ** s,CK_MECHANISM_PTR pMechanism,CK_BYTE_PTR kval,CK_ULONG klen,int opflag)1044072Skrishna do_soft_hmac_init(void **s, CK_MECHANISM_PTR pMechanism,
1054072Skrishna     CK_BYTE_PTR kval, CK_ULONG klen, int opflag)
1064072Skrishna {
1074072Skrishna 	CK_RV rv;
1084072Skrishna 	soft_object_t keyobj;
1094072Skrishna 	secret_key_obj_t skeyobj;
1104072Skrishna 	soft_object_t *key_p;
1114072Skrishna 	soft_session_t *session_p;
1124072Skrishna 
1134072Skrishna 	session_p = *((soft_session_t **)s);
1144072Skrishna 	if (session_p == NULL) {
1154072Skrishna 		session_p = calloc(1, sizeof (soft_session_t));
1164072Skrishna 		/* See comments in do_soft_digest() above */
1174072Skrishna 		if (pthread_mutex_init(&session_p->session_mutex, NULL) != 0) {
1184072Skrishna 			free(session_p);
1194072Skrishna 			return (CKR_CANT_LOCK);
1204072Skrishna 		}
1214072Skrishna 
1224072Skrishna 		*s = session_p;
1234072Skrishna 	} else if (opflag & OP_INIT) {
1244072Skrishna 		free_soft_ctx(session_p, opflag);
1254072Skrishna 	}
1264072Skrishna 
1274072Skrishna 	/* Do the minimum needed setup for the call to succeed */
1284072Skrishna 	key_p = &keyobj;
1294072Skrishna 	bzero(key_p, sizeof (soft_object_t));
1304072Skrishna 	key_p->class = CKO_SECRET_KEY;
1314072Skrishna 	key_p->key_type = CKK_GENERIC_SECRET;
1324072Skrishna 
1334072Skrishna 	bzero(&skeyobj, sizeof (secret_key_obj_t));
1344072Skrishna 	OBJ_SEC(key_p) = &skeyobj;
1354072Skrishna 	OBJ_SEC_VALUE(key_p) = kval;
1364072Skrishna 	OBJ_SEC_VALUE_LEN(key_p) = klen;
1374072Skrishna 
1384072Skrishna 	rv = soft_hmac_sign_verify_init_common(session_p, pMechanism,
1394072Skrishna 	    key_p, opflag & OP_SIGN);
1404072Skrishna 
1414072Skrishna 	return (rv);
1424072Skrishna }
1434072Skrishna 
1444072Skrishna /*
1454072Skrishna  * opflag specifies whether this is a sign or verify.
1464072Skrishna  */
1474072Skrishna CK_RV
do_soft_hmac_update(void ** s,CK_BYTE_PTR pData,CK_ULONG ulDataLen,int opflag)1484072Skrishna do_soft_hmac_update(void **s, CK_BYTE_PTR pData, CK_ULONG ulDataLen, int opflag)
1494072Skrishna {
1504072Skrishna 	soft_session_t *session_p;
1514072Skrishna 
1524072Skrishna 	session_p = *((soft_session_t **)s);
1534072Skrishna 	if (session_p == NULL) {
1544072Skrishna 		return (CKR_ARGUMENTS_BAD);
1554072Skrishna 	}
1564072Skrishna 
1574072Skrishna 	return (soft_hmac_sign_verify_update(session_p,
1584072Skrishna 	    pData, ulDataLen, opflag & OP_SIGN));
1594072Skrishna }
1604072Skrishna 
1614072Skrishna /*
1624072Skrishna  * opflag specifies whether this is a final or single.
1634072Skrishna  */
1644072Skrishna CK_RV
do_soft_hmac_sign(void ** s,CK_BYTE_PTR pData,CK_ULONG ulDataLen,CK_BYTE_PTR pSignature,CK_ULONG_PTR pulSignatureLen,int opflag)1654072Skrishna do_soft_hmac_sign(void **s, CK_BYTE_PTR pData, CK_ULONG ulDataLen,
1664072Skrishna     CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen, int opflag)
1674072Skrishna {
1684072Skrishna 	CK_RV rv;
1694072Skrishna 	soft_session_t *session_p;
1704072Skrishna 	CK_BYTE hmac[SHA512_DIGEST_LENGTH]; /* use the maximum size */
1714072Skrishna 
1724072Skrishna 	session_p = *((soft_session_t **)s);
1734072Skrishna 	if (session_p == NULL || !(opflag & OP_SINGLE || opflag & OP_FINAL)) {
1744072Skrishna 		return (CKR_ARGUMENTS_BAD);
1754072Skrishna 	}
1764072Skrishna 
1774072Skrishna 	rv = soft_hmac_sign_verify_common(session_p, pData, ulDataLen,
1784072Skrishna 	    (pSignature != NULL ? hmac : NULL), pulSignatureLen, B_TRUE);
1794072Skrishna 
1804072Skrishna 	if ((rv == CKR_OK) && (pSignature != NULL)) {
1814072Skrishna 		(void) memcpy(pSignature, hmac, *pulSignatureLen);
1824072Skrishna 	}
1834072Skrishna 
1844072Skrishna 	return (rv);
1854072Skrishna }
1864072Skrishna 
1874072Skrishna /*
1884072Skrishna  * opflag specifies whether this is a final or single.
1894072Skrishna  */
1904072Skrishna CK_RV
do_soft_hmac_verify(void ** s,CK_BYTE_PTR pData,CK_ULONG ulDataLen,CK_BYTE_PTR pSignature,CK_ULONG ulSignatureLen,int opflag)1914072Skrishna do_soft_hmac_verify(void **s, CK_BYTE_PTR pData, CK_ULONG ulDataLen,
1924072Skrishna     CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen, int opflag)
1934072Skrishna {
1944072Skrishna 	CK_RV rv;
1954072Skrishna 	CK_ULONG len;
1964072Skrishna 	soft_session_t *session_p;
1974072Skrishna 	soft_hmac_ctx_t *hmac_ctx;
1984072Skrishna 	CK_BYTE hmac[SHA512_DIGEST_LENGTH]; /* use the maximum size */
1994072Skrishna 
2004072Skrishna 	session_p = *((soft_session_t **)s);
2014072Skrishna 	if (session_p == NULL || !(opflag & OP_SINGLE || opflag & OP_FINAL)) {
2024072Skrishna 		return (CKR_ARGUMENTS_BAD);
2034072Skrishna 	}
2044072Skrishna 
2054072Skrishna 	hmac_ctx = (soft_hmac_ctx_t *)session_p->verify.context;
2064072Skrishna 	len = hmac_ctx->hmac_len;
2074072Skrishna 
2084072Skrishna 	rv = soft_hmac_sign_verify_common(session_p, pData,
2094072Skrishna 	    ulDataLen, hmac, &len, B_FALSE);
2104072Skrishna 
2114072Skrishna 	if (rv == CKR_OK) {
2124072Skrishna 		if (len != ulSignatureLen) {
2134072Skrishna 			rv = CKR_SIGNATURE_LEN_RANGE;
2144072Skrishna 		}
2154072Skrishna 
2164072Skrishna 		if (memcmp(hmac, pSignature, len) != 0) {
2174072Skrishna 			rv = CKR_SIGNATURE_INVALID;
2184072Skrishna 		}
2194072Skrishna 	}
2204072Skrishna 
2214072Skrishna 	return (rv);
2224072Skrishna }
2234072Skrishna 
2244072Skrishna /*
2254072Skrishna  * Helper routine to handle the case when the ctx is abandoned.
2264072Skrishna  */
2274072Skrishna void
free_soft_ctx(void * s,int opflag)2284072Skrishna free_soft_ctx(void *s, int opflag)
2294072Skrishna {
2304072Skrishna 	soft_session_t *session_p;
2314072Skrishna 
2324072Skrishna 	session_p = (soft_session_t *)s;
2334072Skrishna 	if (session_p == NULL)
2344072Skrishna 		return;
2354072Skrishna 
2364072Skrishna 	if (opflag & OP_SIGN) {
2374072Skrishna 		if (session_p->sign.context == NULL)
2384072Skrishna 			return;
2394072Skrishna 		bzero(session_p->sign.context, sizeof (soft_hmac_ctx_t));
2404072Skrishna 		free(session_p->sign.context);
2414072Skrishna 		session_p->sign.context = NULL;
2424072Skrishna 		session_p->sign.flags = 0;
2434072Skrishna 	} else if (opflag & OP_VERIFY) {
2444072Skrishna 		if (session_p->verify.context == NULL)
2454072Skrishna 			return;
2464072Skrishna 		bzero(session_p->verify.context, sizeof (soft_hmac_ctx_t));
2474072Skrishna 		free(session_p->verify.context);
2484072Skrishna 		session_p->verify.context = NULL;
2494072Skrishna 		session_p->verify.flags = 0;
2504072Skrishna 	} else {
2514072Skrishna 		if (session_p->digest.context == NULL)
2524072Skrishna 			return;
2534072Skrishna 		free(session_p->digest.context);
2544072Skrishna 		session_p->digest.context = NULL;
2554072Skrishna 		session_p->digest.flags = 0;
2564072Skrishna 	}
2574072Skrishna }
258