199ebb4caSwyllys /*
2e65e5c2dSWyllys Ingersoll  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
39a767088Shaimay  * Use is subject to license terms.
499ebb4caSwyllys  */
599ebb4caSwyllys /*
699ebb4caSwyllys  * Copyright (c) 1995-2000 Intel Corporation. All rights reserved.
799ebb4caSwyllys  */
899ebb4caSwyllys 
999ebb4caSwyllys #include <kmfapiP.h>
109b37d296Swyllys #include <sha1.h>
1199ebb4caSwyllys #include <security/cryptoki.h>
1299ebb4caSwyllys 
1399ebb4caSwyllys #include <ber_der.h>
1499ebb4caSwyllys 
1599ebb4caSwyllys #define	MAX_PUBLIC_KEY_TEMPLATES    (20)
1699ebb4caSwyllys #define	MAX_PRIVATE_KEY_TEMPLATES   (24)
1799ebb4caSwyllys #define	MAX_SECRET_KEY_TEMPLATES    (24)
1899ebb4caSwyllys 
19e65e5c2dSWyllys Ingersoll typedef struct
20e65e5c2dSWyllys Ingersoll {
21e65e5c2dSWyllys Ingersoll 	KMF_ALGORITHM_INDEX kmfAlgorithmId;
22e65e5c2dSWyllys Ingersoll 	CK_KEY_TYPE ckKeyType;
23e65e5c2dSWyllys Ingersoll 	CK_MECHANISM_TYPE signmech;
24e65e5c2dSWyllys Ingersoll 	CK_MECHANISM_TYPE vfymech;
25e65e5c2dSWyllys Ingersoll 	CK_MECHANISM_TYPE hashmech;
26e65e5c2dSWyllys Ingersoll } ALG_INFO;
27e65e5c2dSWyllys Ingersoll 
28e65e5c2dSWyllys Ingersoll static const ALG_INFO alg_info_map[] = {
29*f810c7e5SToomas Soome 	{ KMF_ALGID_RSA, CKK_RSA, CKM_RSA_PKCS, CKM_RSA_PKCS, 0},
30e65e5c2dSWyllys Ingersoll 	{ KMF_ALGID_DSA, CKK_DSA, CKM_DSA, CKM_DSA, CKM_SHA_1 },
31e65e5c2dSWyllys Ingersoll 	{ KMF_ALGID_ECDSA, CKK_EC, CKM_ECDSA, CKM_ECDSA, CKM_SHA_1 },
32e65e5c2dSWyllys Ingersoll 	{ KMF_ALGID_SHA1WithDSA, CKK_DSA, CKM_DSA, CKM_DSA, CKM_SHA_1 },
33e65e5c2dSWyllys Ingersoll 	{ KMF_ALGID_SHA256WithDSA, CKK_DSA, CKM_DSA, CKM_DSA, CKM_SHA256 },
34e65e5c2dSWyllys Ingersoll 
35e65e5c2dSWyllys Ingersoll 	/*
36e65e5c2dSWyllys Ingersoll 	 * For RSA, the verify can be done using a single mechanism,
37e65e5c2dSWyllys Ingersoll 	 * but signing must be done separately because not all hardware
38e65e5c2dSWyllys Ingersoll 	 * tokens support the combined hash+key operations.
39e65e5c2dSWyllys Ingersoll 	 */
40e65e5c2dSWyllys Ingersoll 	{ KMF_ALGID_MD5WithRSA, CKK_RSA, CKM_RSA_PKCS,
41e65e5c2dSWyllys Ingersoll 	    CKM_MD5_RSA_PKCS, CKM_MD5},
42e65e5c2dSWyllys Ingersoll 	{ KMF_ALGID_SHA1WithRSA, CKK_RSA, CKM_RSA_PKCS,
43e65e5c2dSWyllys Ingersoll 	    CKM_SHA1_RSA_PKCS, CKM_SHA_1},
44e65e5c2dSWyllys Ingersoll 	{ KMF_ALGID_SHA256WithRSA, CKK_RSA, CKM_RSA_PKCS,
45e65e5c2dSWyllys Ingersoll 	    CKM_SHA256_RSA_PKCS, CKM_SHA256},
46e65e5c2dSWyllys Ingersoll 	{ KMF_ALGID_SHA384WithRSA, CKK_RSA, CKM_RSA_PKCS,
47e65e5c2dSWyllys Ingersoll 	    CKM_SHA384_RSA_PKCS, CKM_SHA384},
48e65e5c2dSWyllys Ingersoll 	{ KMF_ALGID_SHA512WithRSA, CKK_RSA, CKM_RSA_PKCS,
49e65e5c2dSWyllys Ingersoll 	    CKM_SHA512_RSA_PKCS, CKM_SHA512},
50e65e5c2dSWyllys Ingersoll 	{ KMF_ALGID_SHA1WithECDSA, CKK_EC, CKM_ECDSA,
51e65e5c2dSWyllys Ingersoll 	    CKM_ECDSA, CKM_SHA_1},
52e65e5c2dSWyllys Ingersoll 	{ KMF_ALGID_SHA256WithECDSA, CKK_EC, CKM_ECDSA,
53e65e5c2dSWyllys Ingersoll 	    CKM_ECDSA, CKM_SHA256},
54e65e5c2dSWyllys Ingersoll 	{ KMF_ALGID_SHA384WithECDSA, CKK_EC, CKM_ECDSA,
55e65e5c2dSWyllys Ingersoll 	    CKM_ECDSA, CKM_SHA384},
56e65e5c2dSWyllys Ingersoll 	{ KMF_ALGID_SHA512WithECDSA, CKK_EC, CKM_ECDSA,
57e65e5c2dSWyllys Ingersoll 	    CKM_ECDSA, CKM_SHA512}
58e65e5c2dSWyllys Ingersoll };
59e65e5c2dSWyllys Ingersoll 
60e65e5c2dSWyllys Ingersoll KMF_RETURN
get_pk11_data(KMF_ALGORITHM_INDEX AlgId,CK_KEY_TYPE * keytype,CK_MECHANISM_TYPE * signmech,CK_MECHANISM_TYPE * hashmech,boolean_t vfy)61e65e5c2dSWyllys Ingersoll get_pk11_data(KMF_ALGORITHM_INDEX AlgId,
62e65e5c2dSWyllys Ingersoll 	CK_KEY_TYPE *keytype, CK_MECHANISM_TYPE *signmech,
63e65e5c2dSWyllys Ingersoll 	CK_MECHANISM_TYPE *hashmech, boolean_t vfy)
64e65e5c2dSWyllys Ingersoll {
65e65e5c2dSWyllys Ingersoll 	uint32_t uIndex;
66e65e5c2dSWyllys Ingersoll 	uint32_t uMapSize =
67e65e5c2dSWyllys Ingersoll 	    sizeof (alg_info_map) / sizeof (ALG_INFO);
68e65e5c2dSWyllys Ingersoll 
69e65e5c2dSWyllys Ingersoll 	for (uIndex = 0; uIndex < uMapSize; uIndex++) {
70e65e5c2dSWyllys Ingersoll 		if (alg_info_map[uIndex].kmfAlgorithmId == AlgId) {
71e65e5c2dSWyllys Ingersoll 			if (keytype)
72e65e5c2dSWyllys Ingersoll 				*keytype = alg_info_map[uIndex].ckKeyType;
73e65e5c2dSWyllys Ingersoll 			if (hashmech)
74e65e5c2dSWyllys Ingersoll 				*hashmech = alg_info_map[uIndex].hashmech;
75e65e5c2dSWyllys Ingersoll 			if (signmech)
76e65e5c2dSWyllys Ingersoll 				*signmech =
77e65e5c2dSWyllys Ingersoll 				    (vfy ? alg_info_map[uIndex].vfymech :
78e65e5c2dSWyllys Ingersoll 				    alg_info_map[uIndex].signmech);
79e65e5c2dSWyllys Ingersoll 			return (KMF_OK);
80e65e5c2dSWyllys Ingersoll 		}
81e65e5c2dSWyllys Ingersoll 	}
82e65e5c2dSWyllys Ingersoll 	/* no match */
83e65e5c2dSWyllys Ingersoll 	return (KMF_ERR_BAD_ALGORITHM);
84e65e5c2dSWyllys Ingersoll }
85e65e5c2dSWyllys Ingersoll 
86e65e5c2dSWyllys Ingersoll KMF_RETURN
kmf_create_pk11_session(CK_SESSION_HANDLE * sessionp,CK_MECHANISM_TYPE wanted_mech,CK_FLAGS wanted_flags)87e65e5c2dSWyllys Ingersoll kmf_create_pk11_session(CK_SESSION_HANDLE *sessionp,
88e65e5c2dSWyllys Ingersoll 	CK_MECHANISM_TYPE wanted_mech,
8999ebb4caSwyllys 	CK_FLAGS wanted_flags)
9099ebb4caSwyllys {
9199ebb4caSwyllys 	CK_RV rv;
929b37d296Swyllys 	KMF_RETURN ret;
9399ebb4caSwyllys 	KMF_RETURN kmf_rv = KMF_OK;
9499ebb4caSwyllys 	CK_SLOT_ID_PTR pSlotList;
9599ebb4caSwyllys 	CK_ULONG pulCount;
9699ebb4caSwyllys 	CK_MECHANISM_INFO info;
9799ebb4caSwyllys 	int i;
9899ebb4caSwyllys 
999b37d296Swyllys 	ret = init_pk11();
1009b37d296Swyllys 
1019b37d296Swyllys 	if (ret != KMF_OK)
1029b37d296Swyllys 		return (ret);
10399ebb4caSwyllys 
10499ebb4caSwyllys 	rv = C_GetSlotList(0, NULL, &pulCount);
10599ebb4caSwyllys 	if (rv != CKR_OK) {
10699ebb4caSwyllys 		kmf_rv = KMF_ERR_UNINITIALIZED;
10799ebb4caSwyllys 		goto out;
10899ebb4caSwyllys 	}
10999ebb4caSwyllys 
11099ebb4caSwyllys 	pSlotList = (CK_SLOT_ID_PTR) malloc(pulCount * sizeof (CK_SLOT_ID));
11199ebb4caSwyllys 	if (pSlotList == NULL) {
11299ebb4caSwyllys 		kmf_rv = KMF_ERR_MEMORY;
11399ebb4caSwyllys 		goto out;
11499ebb4caSwyllys 	}
11599ebb4caSwyllys 
11699ebb4caSwyllys 	rv = C_GetSlotList(0, pSlotList, &pulCount);
11799ebb4caSwyllys 	if (rv != CKR_OK) {
11899ebb4caSwyllys 		kmf_rv = KMF_ERR_UNINITIALIZED;
11999ebb4caSwyllys 		goto out;
12099ebb4caSwyllys 	}
12199ebb4caSwyllys 
12299ebb4caSwyllys 	for (i = 0; i < pulCount; i++) {
12399ebb4caSwyllys 		rv = C_GetMechanismInfo(pSlotList[i], wanted_mech, &info);
124e65e5c2dSWyllys Ingersoll 		if (rv == CKR_OK &&
125e65e5c2dSWyllys Ingersoll 		    (info.flags & wanted_flags) == wanted_flags)
12699ebb4caSwyllys 			break;
12799ebb4caSwyllys 	}
12899ebb4caSwyllys 	if (i < pulCount) {
12999ebb4caSwyllys 		rv = C_OpenSession(pSlotList[i], CKF_SERIAL_SESSION,
13030a5e8faSwyllys 		    NULL, NULL, sessionp);
13199ebb4caSwyllys 
13299ebb4caSwyllys 		if (rv != CKR_OK) {
13399ebb4caSwyllys 			kmf_rv = KMF_ERR_UNINITIALIZED;
13499ebb4caSwyllys 		}
13599ebb4caSwyllys 	} else {
13699ebb4caSwyllys 		kmf_rv = KMF_ERR_UNINITIALIZED;
13799ebb4caSwyllys 	}
13899ebb4caSwyllys 
13999ebb4caSwyllys out:
14099ebb4caSwyllys 	if (pSlotList != NULL)
14199ebb4caSwyllys 		free(pSlotList);
14299ebb4caSwyllys 	return (kmf_rv);
14399ebb4caSwyllys 
14499ebb4caSwyllys }
14599ebb4caSwyllys 
14699ebb4caSwyllys /*
14799ebb4caSwyllys  * Name: PKCS_AddTemplate
14899ebb4caSwyllys  *
14999ebb4caSwyllys  * Description:
15099ebb4caSwyllys  *  Adds a CK_ATTRIBUTE value to an existing array of CK_ATTRIBUTES. Will
15199ebb4caSwyllys  *  not expand the array beyond the maximum specified size.
15299ebb4caSwyllys  *
15399ebb4caSwyllys  * Returns:
15499ebb4caSwyllys  *  TRUE - Attribute value succesfully added.
15599ebb4caSwyllys  *  FALSE - Maximum array size would be exceded.
15699ebb4caSwyllys  */
15799ebb4caSwyllys static int
PKCS_AddTemplate(CK_ATTRIBUTE * pTemplate,CK_ULONG * ckNumTemplates,CK_ULONG ckMaxTemplates,CK_ATTRIBUTE_TYPE ckAttribCode,CK_BYTE * pckBuffer,CK_ULONG ckBufferLen)15899ebb4caSwyllys PKCS_AddTemplate(CK_ATTRIBUTE *pTemplate,
15999ebb4caSwyllys 	CK_ULONG *ckNumTemplates,
16099ebb4caSwyllys 	CK_ULONG ckMaxTemplates,
16199ebb4caSwyllys 	CK_ATTRIBUTE_TYPE ckAttribCode,
16299ebb4caSwyllys 	CK_BYTE * pckBuffer,
16399ebb4caSwyllys 	CK_ULONG ckBufferLen)
16499ebb4caSwyllys {
16599ebb4caSwyllys 	if (*ckNumTemplates >= ckMaxTemplates) {
16699ebb4caSwyllys 		return (FALSE);
16799ebb4caSwyllys 	}
16899ebb4caSwyllys 
16999ebb4caSwyllys 	pTemplate[*ckNumTemplates].type = ckAttribCode;
17099ebb4caSwyllys 	pTemplate[*ckNumTemplates].pValue = pckBuffer;
17199ebb4caSwyllys 	pTemplate[*ckNumTemplates].ulValueLen = ckBufferLen;
17299ebb4caSwyllys 	(*ckNumTemplates)++;
17399ebb4caSwyllys 
17499ebb4caSwyllys 	return (TRUE);
17599ebb4caSwyllys }
17699ebb4caSwyllys 
17799ebb4caSwyllys /*
17899ebb4caSwyllys  * Convert an SPKI data record to PKCS#11
17999ebb4caSwyllys  * public key object.
18099ebb4caSwyllys  */
18199ebb4caSwyllys static KMF_RETURN
PKCS_CreatePublicKey(const KMF_X509_SPKI * pKey,CK_SESSION_HANDLE ckSession,CK_OBJECT_HANDLE * pckPublicKey)18299ebb4caSwyllys PKCS_CreatePublicKey(
18399ebb4caSwyllys 	const KMF_X509_SPKI *pKey,
18499ebb4caSwyllys 	CK_SESSION_HANDLE ckSession,
18599ebb4caSwyllys 	CK_OBJECT_HANDLE *pckPublicKey)
18699ebb4caSwyllys {
18799ebb4caSwyllys 	KMF_RETURN mrReturn = KMF_OK;
18899ebb4caSwyllys 	CK_RV ckRv;
18999ebb4caSwyllys 
19099ebb4caSwyllys 	CK_ATTRIBUTE ckTemplate[MAX_PUBLIC_KEY_TEMPLATES];
19199ebb4caSwyllys 	CK_ULONG ckNumTemplates = 0;
19299ebb4caSwyllys 
19399ebb4caSwyllys 	/* Common object attributes */
19499ebb4caSwyllys 	CK_OBJECT_CLASS ckObjClass = CKO_PUBLIC_KEY;
19599ebb4caSwyllys 	CK_BBOOL ckToken = 0;
19699ebb4caSwyllys 	CK_BBOOL ckPrivate = 0;
19799ebb4caSwyllys 
19899ebb4caSwyllys 	/* Common key attributes */
19999ebb4caSwyllys 	CK_KEY_TYPE ckKeyType;
20099ebb4caSwyllys 	CK_BBOOL ckDerive = CK_FALSE;
20199ebb4caSwyllys 
20299ebb4caSwyllys 	/* Common public key attributes */
20399ebb4caSwyllys 	CK_BBOOL ckEncrypt = 1;
20499ebb4caSwyllys 	CK_BBOOL ckVerify = 1;
20599ebb4caSwyllys 
20699ebb4caSwyllys 	CK_BBOOL ckVerifyRecover = CK_FALSE;
20799ebb4caSwyllys 	CK_BBOOL ckWrap = CK_FALSE;
20899ebb4caSwyllys 
20999ebb4caSwyllys 	/* Key part array */
21099ebb4caSwyllys 	KMF_DATA KeyParts[KMF_MAX_PUBLIC_KEY_PARTS];
21199ebb4caSwyllys 	uint32_t i, uNumKeyParts = KMF_MAX_PUBLIC_KEY_PARTS;
21299ebb4caSwyllys 	KMF_ALGORITHM_INDEX AlgorithmId;
21399ebb4caSwyllys 
21499ebb4caSwyllys 	/* Parse the keyblob */
21599ebb4caSwyllys 	(void) memset(KeyParts, 0, sizeof (KeyParts));
21699ebb4caSwyllys 
21730a5e8faSwyllys 	AlgorithmId = x509_algoid_to_algid(
21830a5e8faSwyllys 	    (KMF_OID *)&pKey->algorithm.algorithm);
21930a5e8faSwyllys 	if (AlgorithmId == KMF_ALGID_NONE)
22030a5e8faSwyllys 		return (KMF_ERR_BAD_ALGORITHM);
22199ebb4caSwyllys 
22299ebb4caSwyllys 	mrReturn = ExtractSPKIData(pKey, AlgorithmId, KeyParts, &uNumKeyParts);
22399ebb4caSwyllys 
22499ebb4caSwyllys 	if (mrReturn != KMF_OK)
22599ebb4caSwyllys 		return (mrReturn);
22699ebb4caSwyllys 
22799ebb4caSwyllys 	/* Fill in the common object attributes */
22830a5e8faSwyllys 	if (!PKCS_AddTemplate(ckTemplate, &ckNumTemplates,
22930a5e8faSwyllys 	    MAX_PUBLIC_KEY_TEMPLATES, CKA_CLASS, (CK_BYTE *)&ckObjClass,
23030a5e8faSwyllys 	    sizeof (ckObjClass)) ||
23130a5e8faSwyllys 	    !PKCS_AddTemplate(ckTemplate, &ckNumTemplates,
23230a5e8faSwyllys 	    MAX_PUBLIC_KEY_TEMPLATES, CKA_TOKEN, (CK_BYTE *)&ckToken,
23330a5e8faSwyllys 	    sizeof (ckToken)) ||
23430a5e8faSwyllys 	    !PKCS_AddTemplate(ckTemplate, &ckNumTemplates,
23530a5e8faSwyllys 	    MAX_PUBLIC_KEY_TEMPLATES, CKA_PRIVATE, (CK_BYTE *)&ckPrivate,
23630a5e8faSwyllys 	    sizeof (ckPrivate))) {
23799ebb4caSwyllys 		mrReturn = KMF_ERR_INTERNAL;
23899ebb4caSwyllys 		goto cleanup;
23999ebb4caSwyllys 	}
24099ebb4caSwyllys 
24199ebb4caSwyllys 	/* Fill in the common key attributes */
242e65e5c2dSWyllys Ingersoll 	if (get_pk11_data(AlgorithmId, &ckKeyType, NULL, NULL, 0)) {
24399ebb4caSwyllys 		goto cleanup;
24499ebb4caSwyllys 	}
24530a5e8faSwyllys 	if (!PKCS_AddTemplate(ckTemplate, &ckNumTemplates,
24630a5e8faSwyllys 	    MAX_PUBLIC_KEY_TEMPLATES, CKA_KEY_TYPE, (CK_BYTE *)&ckKeyType,
24730a5e8faSwyllys 	    sizeof (ckKeyType)) ||
24830a5e8faSwyllys 	    !PKCS_AddTemplate(ckTemplate, &ckNumTemplates,
24930a5e8faSwyllys 	    MAX_PUBLIC_KEY_TEMPLATES, CKA_DERIVE, (CK_BYTE *)&ckDerive,
25030a5e8faSwyllys 	    sizeof (ckDerive))) {
25199ebb4caSwyllys 		mrReturn = KMF_ERR_INTERNAL;
25299ebb4caSwyllys 		goto cleanup;
25399ebb4caSwyllys 	}
25499ebb4caSwyllys 
25599ebb4caSwyllys 	/* Add common public key attributes */
25630a5e8faSwyllys 	if (!PKCS_AddTemplate(ckTemplate, &ckNumTemplates,
25730a5e8faSwyllys 	    MAX_PUBLIC_KEY_TEMPLATES, CKA_ENCRYPT, (CK_BYTE *)&ckEncrypt,
25830a5e8faSwyllys 	    sizeof (ckEncrypt)) ||
25930a5e8faSwyllys 	    !PKCS_AddTemplate(ckTemplate, &ckNumTemplates,
26030a5e8faSwyllys 	    MAX_PUBLIC_KEY_TEMPLATES, CKA_VERIFY, (CK_BYTE *)&ckVerify,
26130a5e8faSwyllys 	    sizeof (ckVerify)) ||
26230a5e8faSwyllys 	    !PKCS_AddTemplate(ckTemplate, &ckNumTemplates,
26330a5e8faSwyllys 	    MAX_PUBLIC_KEY_TEMPLATES, CKA_VERIFY_RECOVER,
26430a5e8faSwyllys 	    (CK_BYTE *)&ckVerifyRecover, sizeof (ckVerifyRecover)) ||
26530a5e8faSwyllys 	    !PKCS_AddTemplate(ckTemplate, &ckNumTemplates,
26630a5e8faSwyllys 	    MAX_PUBLIC_KEY_TEMPLATES, CKA_WRAP, (CK_BYTE *)&ckWrap,
26730a5e8faSwyllys 	    sizeof (ckWrap))) {
26899ebb4caSwyllys 		mrReturn = KMF_ERR_INTERNAL;
26999ebb4caSwyllys 		goto cleanup;
27099ebb4caSwyllys 	}
27199ebb4caSwyllys 
27299ebb4caSwyllys 	/* Add algorithm specific attributes */
27399ebb4caSwyllys 	switch (ckKeyType) {
27499ebb4caSwyllys 	case CKK_RSA:
27530a5e8faSwyllys 		if (!PKCS_AddTemplate(ckTemplate, &ckNumTemplates,
27630a5e8faSwyllys 		    MAX_PUBLIC_KEY_TEMPLATES, CKA_MODULUS,
27730a5e8faSwyllys 		    (CK_BYTE *)KeyParts[KMF_RSA_MODULUS].Data,
27830a5e8faSwyllys 		    (CK_ULONG)KeyParts[KMF_RSA_MODULUS].Length) ||
279e65e5c2dSWyllys Ingersoll 
28030a5e8faSwyllys 		    !PKCS_AddTemplate(ckTemplate, &ckNumTemplates,
28130a5e8faSwyllys 		    MAX_PUBLIC_KEY_TEMPLATES, CKA_PUBLIC_EXPONENT,
28230a5e8faSwyllys 		    (CK_BYTE *)KeyParts[KMF_RSA_PUBLIC_EXPONENT].Data,
28330a5e8faSwyllys 		    (CK_ULONG)KeyParts[KMF_RSA_PUBLIC_EXPONENT].Length)) {
28430a5e8faSwyllys 			mrReturn = KMF_ERR_INTERNAL;
28530a5e8faSwyllys 			goto cleanup;
28699ebb4caSwyllys 		}
28799ebb4caSwyllys 		break;
28899ebb4caSwyllys 	case CKK_DSA:
28930a5e8faSwyllys 		if (!PKCS_AddTemplate(ckTemplate, &ckNumTemplates,
29030a5e8faSwyllys 		    MAX_PUBLIC_KEY_TEMPLATES, CKA_PRIME,
29130a5e8faSwyllys 		    (CK_BYTE *)KeyParts[KMF_DSA_PRIME].Data,
29230a5e8faSwyllys 		    (CK_ULONG)KeyParts[KMF_DSA_PRIME].Length) ||
29330a5e8faSwyllys 		    !PKCS_AddTemplate(ckTemplate, &ckNumTemplates,
29430a5e8faSwyllys 		    MAX_PUBLIC_KEY_TEMPLATES, CKA_SUBPRIME,
29530a5e8faSwyllys 		    (CK_BYTE *)KeyParts[KMF_DSA_SUB_PRIME].Data,
29630a5e8faSwyllys 		    (CK_ULONG)KeyParts[KMF_DSA_SUB_PRIME].Length) ||
29730a5e8faSwyllys 		    !PKCS_AddTemplate(ckTemplate, &ckNumTemplates,
29830a5e8faSwyllys 		    MAX_PUBLIC_KEY_TEMPLATES, CKA_BASE,
29930a5e8faSwyllys 		    (CK_BYTE *)KeyParts[KMF_DSA_BASE].Data,
30030a5e8faSwyllys 		    (CK_ULONG)KeyParts[KMF_DSA_BASE].Length) ||
30130a5e8faSwyllys 		    !PKCS_AddTemplate(ckTemplate, &ckNumTemplates,
30230a5e8faSwyllys 		    MAX_PUBLIC_KEY_TEMPLATES, CKA_VALUE,
30330a5e8faSwyllys 		    (CK_BYTE *)KeyParts[KMF_DSA_PUBLIC_VALUE].Data,
30430a5e8faSwyllys 		    (CK_ULONG)KeyParts[KMF_DSA_PUBLIC_VALUE].Length)) {
30599ebb4caSwyllys 		mrReturn = KMF_ERR_INTERNAL;
30699ebb4caSwyllys 		goto cleanup;
30799ebb4caSwyllys 		}
30899ebb4caSwyllys 		break;
309e65e5c2dSWyllys Ingersoll 	case CKK_EC:
310e65e5c2dSWyllys Ingersoll 		if (!PKCS_AddTemplate(ckTemplate, &ckNumTemplates,
311e65e5c2dSWyllys Ingersoll 		    MAX_PUBLIC_KEY_TEMPLATES, CKA_EC_POINT,
312e65e5c2dSWyllys Ingersoll 		    (CK_BYTE *)KeyParts[KMF_ECDSA_POINT].Data,
313e65e5c2dSWyllys Ingersoll 		    (CK_ULONG)KeyParts[KMF_ECDSA_POINT].Length) ||
314e65e5c2dSWyllys Ingersoll 
315e65e5c2dSWyllys Ingersoll 		    !PKCS_AddTemplate(ckTemplate, &ckNumTemplates,
316e65e5c2dSWyllys Ingersoll 		    MAX_PUBLIC_KEY_TEMPLATES, CKA_EC_PARAMS,
317e65e5c2dSWyllys Ingersoll 		    (CK_BYTE *)KeyParts[KMF_ECDSA_PARAMS].Data,
318e65e5c2dSWyllys Ingersoll 		    (CK_ULONG)KeyParts[KMF_ECDSA_PARAMS].Length)) {
319e65e5c2dSWyllys Ingersoll 			mrReturn = KMF_ERR_INTERNAL;
320e65e5c2dSWyllys Ingersoll 			goto cleanup;
321e65e5c2dSWyllys Ingersoll 		}
322e65e5c2dSWyllys Ingersoll 		break;
32399ebb4caSwyllys 	default:
32499ebb4caSwyllys 		mrReturn = KMF_ERR_BAD_PARAMETER;
32599ebb4caSwyllys 	}
32699ebb4caSwyllys 
32799ebb4caSwyllys 	if (mrReturn == KMF_OK) {
32899ebb4caSwyllys 		/* Instantiate the object */
32930a5e8faSwyllys 		ckRv = C_CreateObject(ckSession, ckTemplate,
33030a5e8faSwyllys 		    ckNumTemplates, pckPublicKey);
33199ebb4caSwyllys 		if (ckRv != CKR_OK)
33299ebb4caSwyllys 			mrReturn = KMF_ERR_INTERNAL;
33399ebb4caSwyllys 	}
33499ebb4caSwyllys 
33599ebb4caSwyllys cleanup:
33699ebb4caSwyllys 	for (i = 0; i < uNumKeyParts; i++) {
33730a5e8faSwyllys 		kmf_free_data(&KeyParts[i]);
33899ebb4caSwyllys 	}
33999ebb4caSwyllys 
34099ebb4caSwyllys 	return (mrReturn);
34199ebb4caSwyllys }
34299ebb4caSwyllys 
34399ebb4caSwyllys /*
34499ebb4caSwyllys  * PKCS_AcquirePublicKeyHandle
34599ebb4caSwyllys  *
34699ebb4caSwyllys  *   Given an assymetric key keyblob, attempts to find the appropriate
34799ebb4caSwyllys  *    public key.
34899ebb4caSwyllys  *
34999ebb4caSwyllys  *  Methods of finding the public key:
35099ebb4caSwyllys  *  - Public Key with data present:
35199ebb4caSwyllys  *    Parses the key and creates a temporary session object.
35299ebb4caSwyllys  *  - Public Key with handle:
35399ebb4caSwyllys  *    The handle is type converted and returned. Validity of the handle is
35499ebb4caSwyllys  *    not checked.
35599ebb4caSwyllys  *  - Public Key with label:
35699ebb4caSwyllys  *    Attempts to find a public key with the corresponding label.
35799ebb4caSwyllys  */
358e65e5c2dSWyllys Ingersoll static KMF_RETURN
PKCS_AcquirePublicKeyHandle(CK_SESSION_HANDLE ckSession,const KMF_X509_SPKI * pKey,CK_KEY_TYPE ckRequestedKeyType,CK_OBJECT_HANDLE * pckKeyHandle)35999ebb4caSwyllys PKCS_AcquirePublicKeyHandle(CK_SESSION_HANDLE ckSession,
36099ebb4caSwyllys 	const KMF_X509_SPKI *pKey,
36199ebb4caSwyllys 	CK_KEY_TYPE ckRequestedKeyType,
362e65e5c2dSWyllys Ingersoll 	CK_OBJECT_HANDLE *pckKeyHandle)
36399ebb4caSwyllys {
36499ebb4caSwyllys 	KMF_RETURN mrReturn = KMF_OK;
36599ebb4caSwyllys 
36699ebb4caSwyllys 	/* Key searching variables */
367e65e5c2dSWyllys Ingersoll 	CK_OBJECT_HANDLE ckKeyHandle = 0;
36899ebb4caSwyllys 	CK_OBJECT_CLASS ckObjClass;
36999ebb4caSwyllys 	CK_KEY_TYPE ckKeyType;
37099ebb4caSwyllys 	CK_ATTRIBUTE ckTemplate[3];
37199ebb4caSwyllys 	CK_ULONG ckNumTemplates;
37299ebb4caSwyllys 	static const CK_ULONG ckMaxTemplates = (sizeof (ckTemplate) /
37330a5e8faSwyllys 	    sizeof (CK_ATTRIBUTE));
37499ebb4caSwyllys 	CK_RV ckRv;
37599ebb4caSwyllys 
37699ebb4caSwyllys 	/* Extract the data from the SPKI into individual fields */
37799ebb4caSwyllys 	mrReturn = PKCS_CreatePublicKey(pKey, ckSession, &ckKeyHandle);
37899ebb4caSwyllys 	if (mrReturn != KMF_OK)
37999ebb4caSwyllys 		return (mrReturn);
38099ebb4caSwyllys 
38199ebb4caSwyllys 	/* Fetch the key class and algorithm from the object */
38299ebb4caSwyllys 	ckNumTemplates = 0;
38330a5e8faSwyllys 	if (!PKCS_AddTemplate(ckTemplate, &ckNumTemplates,
38430a5e8faSwyllys 	    ckMaxTemplates, CKA_CLASS, (CK_BYTE *)&ckObjClass,
38530a5e8faSwyllys 	    sizeof (ckObjClass)) ||
38630a5e8faSwyllys 	    !PKCS_AddTemplate(ckTemplate, &ckNumTemplates,
38730a5e8faSwyllys 	    ckMaxTemplates, CKA_KEY_TYPE, (CK_BYTE *)&ckKeyType,
38830a5e8faSwyllys 	    sizeof (ckKeyType))) {
389e65e5c2dSWyllys Ingersoll 		(void) C_DestroyObject(ckSession, ckKeyHandle);
39099ebb4caSwyllys 		return (KMF_ERR_INTERNAL);
39199ebb4caSwyllys 	}
39230a5e8faSwyllys 	ckRv = C_GetAttributeValue(ckSession, ckKeyHandle,
39330a5e8faSwyllys 	    ckTemplate,	ckNumTemplates);
39499ebb4caSwyllys 	if (ckRv != CKR_OK) {
395e65e5c2dSWyllys Ingersoll 		(void) C_DestroyObject(ckSession, ckKeyHandle);
39699ebb4caSwyllys 		return (ckRv);
39799ebb4caSwyllys 	}
39899ebb4caSwyllys 
39999ebb4caSwyllys 	/* Make sure the results match the expected values */
40099ebb4caSwyllys 	if ((ckKeyType != ckRequestedKeyType) ||
40130a5e8faSwyllys 	    (ckObjClass != CKO_PUBLIC_KEY)) {
402e65e5c2dSWyllys Ingersoll 		(void) C_DestroyObject(ckSession, ckKeyHandle);
40399ebb4caSwyllys 		return (KMF_ERR_BAD_KEY_FORMAT);
40499ebb4caSwyllys 	}
40599ebb4caSwyllys 
40699ebb4caSwyllys 	/* Set the return values */
40799ebb4caSwyllys 	*pckKeyHandle = ckKeyHandle;
40899ebb4caSwyllys 
40999ebb4caSwyllys 	return (KMF_OK);
41099ebb4caSwyllys }
41199ebb4caSwyllys 
412e65e5c2dSWyllys Ingersoll /*
413e65e5c2dSWyllys Ingersoll  * Utility routine for verifying generic data using
414e65e5c2dSWyllys Ingersoll  * the cryptographic framework (PKCS#11).
415e65e5c2dSWyllys Ingersoll  * There are situations where we want to force this
416e65e5c2dSWyllys Ingersoll  * operation to happen in a specific keystore.
417e65e5c2dSWyllys Ingersoll  * For example:
418e65e5c2dSWyllys Ingersoll  * libelfsign.so.1 verifies signatures on crypto libraries.
419e65e5c2dSWyllys Ingersoll  * We must use pkcs11 functions to verify the pkcs11
420e65e5c2dSWyllys Ingersoll  * plugins in order to keep the validation within the
421e65e5c2dSWyllys Ingersoll  * Cryptographic Framework's FIPS-140 boundary. To avoid
422e65e5c2dSWyllys Ingersoll  * a circular dependency, pksc11_softtoken.so.1 is
423e65e5c2dSWyllys Ingersoll  * interposed by libkcfd.so.1 via kcfd, which prevents
424e65e5c2dSWyllys Ingersoll  * libpkcs11.so.1's interfaces from being used when libkmf.so.1
425e65e5c2dSWyllys Ingersoll  * is called from kcfd.
426e65e5c2dSWyllys Ingersoll  *
427e65e5c2dSWyllys Ingersoll  * This also saves code and time because verify operations
428e65e5c2dSWyllys Ingersoll  * only use public keys and do not need acccess to any
429e65e5c2dSWyllys Ingersoll  * keystore specific functions.
430e65e5c2dSWyllys Ingersoll  */
43199ebb4caSwyllys KMF_RETURN
PKCS_VerifyData(KMF_HANDLE_T handle,KMF_ALGORITHM_INDEX AlgorithmId,KMF_X509_SPKI * keyp,KMF_DATA * data,KMF_DATA * signature)432e65e5c2dSWyllys Ingersoll PKCS_VerifyData(KMF_HANDLE_T handle,
43399ebb4caSwyllys 		KMF_ALGORITHM_INDEX AlgorithmId,
43499ebb4caSwyllys 		KMF_X509_SPKI *keyp,
43599ebb4caSwyllys 		KMF_DATA *data,
436e65e5c2dSWyllys Ingersoll 		KMF_DATA *signature)
43799ebb4caSwyllys {
438e65e5c2dSWyllys Ingersoll 	KMF_RETURN	rv = KMF_OK;
439e65e5c2dSWyllys Ingersoll 	CK_RV		ckRv;
440e65e5c2dSWyllys Ingersoll 	KMF_HANDLE	*kmfh = (KMF_HANDLE *)handle;
441e65e5c2dSWyllys Ingersoll 	CK_MECHANISM	ckMechanism;
442e65e5c2dSWyllys Ingersoll 	CK_MECHANISM_TYPE mechtype, hashmech;
443e65e5c2dSWyllys Ingersoll 	CK_OBJECT_HANDLE ckKeyHandle = 0;
444e65e5c2dSWyllys Ingersoll 	CK_KEY_TYPE	pk11keytype;
44599ebb4caSwyllys 	CK_SESSION_HANDLE ckSession = 0;
446e65e5c2dSWyllys Ingersoll 	CK_ATTRIBUTE	subprime = { CKA_SUBPRIME, NULL, 0 };
447e65e5c2dSWyllys Ingersoll 	CK_BYTE		*dataptr;
448e65e5c2dSWyllys Ingersoll 	CK_ULONG	datalen;
4496b35cb3cSRichard PALO 	KMF_DATA	hashData = { 0, NULL };
450e65e5c2dSWyllys Ingersoll 	uchar_t		digest[1024];
45199ebb4caSwyllys 
45299ebb4caSwyllys 	if (AlgorithmId == KMF_ALGID_NONE)
45399ebb4caSwyllys 		return (KMF_ERR_BAD_ALGORITHM);
45499ebb4caSwyllys 
455e65e5c2dSWyllys Ingersoll 	if (get_pk11_data(AlgorithmId, &pk11keytype, &mechtype, &hashmech, 1))
45699ebb4caSwyllys 		return (KMF_ERR_BAD_ALGORITHM);
45799ebb4caSwyllys 
458e65e5c2dSWyllys Ingersoll 	/*
459e65e5c2dSWyllys Ingersoll 	 * Verify in metaslot/softtoken since only the public key is needed
460e65e5c2dSWyllys Ingersoll 	 * and not all hardware tokens support the combined [hash]-RSA/DSA/EC
461e65e5c2dSWyllys Ingersoll 	 * mechanisms.
462e65e5c2dSWyllys Ingersoll 	 */
463e65e5c2dSWyllys Ingersoll 	rv = kmf_create_pk11_session(&ckSession, mechtype, 0);
46499ebb4caSwyllys 	if (rv != KMF_OK)
46599ebb4caSwyllys 		return (rv);
46699ebb4caSwyllys 
46799ebb4caSwyllys 	/* Fetch the verifying key */
46899ebb4caSwyllys 	rv = PKCS_AcquirePublicKeyHandle(ckSession, keyp,
469e65e5c2dSWyllys Ingersoll 	    pk11keytype, &ckKeyHandle);
47099ebb4caSwyllys 
47199ebb4caSwyllys 	if (rv != KMF_OK) {
47299ebb4caSwyllys 		(void) C_CloseSession(ckSession);
47399ebb4caSwyllys 		return (rv);
47499ebb4caSwyllys 	}
475e65e5c2dSWyllys Ingersoll 	dataptr = data->Data;
476e65e5c2dSWyllys Ingersoll 	datalen = data->Length;
477e65e5c2dSWyllys Ingersoll 	/*
478e65e5c2dSWyllys Ingersoll 	 * For some mechanisms, we must compute the hash separately
479e65e5c2dSWyllys Ingersoll 	 * and then do the verify.
480e65e5c2dSWyllys Ingersoll 	 */
481e65e5c2dSWyllys Ingersoll 	if (hashmech != 0 &&
482e65e5c2dSWyllys Ingersoll 	    (mechtype == CKM_ECDSA ||
483e65e5c2dSWyllys Ingersoll 	    mechtype == CKM_DSA ||
484e65e5c2dSWyllys Ingersoll 	    mechtype == CKM_RSA_PKCS)) {
485e65e5c2dSWyllys Ingersoll 		hashData.Data = digest;
486e65e5c2dSWyllys Ingersoll 		hashData.Length = sizeof (digest);
487e65e5c2dSWyllys Ingersoll 
488e65e5c2dSWyllys Ingersoll 		rv = PKCS_DigestData(handle, ckSession,
489e65e5c2dSWyllys Ingersoll 		    hashmech, data, &hashData,
490e65e5c2dSWyllys Ingersoll 		    (mechtype == CKM_RSA_PKCS));
491e65e5c2dSWyllys Ingersoll 		if (rv)
492e65e5c2dSWyllys Ingersoll 			goto cleanup;
49399ebb4caSwyllys 
494e65e5c2dSWyllys Ingersoll 		dataptr = hashData.Data;
495e65e5c2dSWyllys Ingersoll 		datalen = hashData.Length;
496e65e5c2dSWyllys Ingersoll 	}
497e65e5c2dSWyllys Ingersoll 	if (mechtype == CKM_DSA &&
498e65e5c2dSWyllys Ingersoll 	    hashmech == CKM_SHA256) {
499e65e5c2dSWyllys Ingersoll 		/*
500e65e5c2dSWyllys Ingersoll 		 * FIPS 186-3 says that when using DSA
501e65e5c2dSWyllys Ingersoll 		 * the hash must be truncated to the size of the
502e65e5c2dSWyllys Ingersoll 		 * subprime.
503e65e5c2dSWyllys Ingersoll 		 */
504e65e5c2dSWyllys Ingersoll 		ckRv = C_GetAttributeValue(ckSession,
505e65e5c2dSWyllys Ingersoll 		    ckKeyHandle, &subprime, 1);
506e65e5c2dSWyllys Ingersoll 		if (ckRv != CKR_OK)  {
507e65e5c2dSWyllys Ingersoll 			kmfh->lasterr.kstype = KMF_KEYSTORE_PK11TOKEN;
508e65e5c2dSWyllys Ingersoll 			kmfh->lasterr.errcode = ckRv;
509e65e5c2dSWyllys Ingersoll 			rv = KMF_ERR_INTERNAL;
510e65e5c2dSWyllys Ingersoll 			goto cleanup;
511e65e5c2dSWyllys Ingersoll 		}
512e65e5c2dSWyllys Ingersoll 		datalen = subprime.ulValueLen;
513e65e5c2dSWyllys Ingersoll 	}
514e65e5c2dSWyllys Ingersoll 
515e65e5c2dSWyllys Ingersoll 	ckMechanism.mechanism = mechtype;
51699ebb4caSwyllys 	ckMechanism.pParameter = NULL;
51799ebb4caSwyllys 	ckMechanism.ulParameterLen = 0;
51899ebb4caSwyllys 
51999ebb4caSwyllys 	ckRv = C_VerifyInit(ckSession, &ckMechanism, ckKeyHandle);
52099ebb4caSwyllys 	if (ckRv != CKR_OK) {
52199ebb4caSwyllys 		kmfh->lasterr.kstype = KMF_KEYSTORE_PK11TOKEN;
52299ebb4caSwyllys 		kmfh->lasterr.errcode = ckRv;
523e65e5c2dSWyllys Ingersoll 		rv = KMF_ERR_INTERNAL;
524e65e5c2dSWyllys Ingersoll 		goto cleanup;
52599ebb4caSwyllys 	}
526e65e5c2dSWyllys Ingersoll 	ckRv = C_Verify(ckSession,
527e65e5c2dSWyllys Ingersoll 	    dataptr, datalen,
528e65e5c2dSWyllys Ingersoll 	    (CK_BYTE *)signature->Data,
529e65e5c2dSWyllys Ingersoll 	    (CK_ULONG)signature->Length);
53099ebb4caSwyllys 
53199ebb4caSwyllys 	if (ckRv != CKR_OK) {
53299ebb4caSwyllys 		kmfh->lasterr.kstype = KMF_KEYSTORE_PK11TOKEN;
53399ebb4caSwyllys 		kmfh->lasterr.errcode = ckRv;
53499ebb4caSwyllys 		rv = KMF_ERR_INTERNAL;
53599ebb4caSwyllys 	}
53699ebb4caSwyllys 
537e65e5c2dSWyllys Ingersoll cleanup:
538e65e5c2dSWyllys Ingersoll 	if (ckKeyHandle != 0)
539e65e5c2dSWyllys Ingersoll 		(void) C_DestroyObject(ckSession, ckKeyHandle);
54099ebb4caSwyllys 	(void) C_CloseSession(ckSession);
54199ebb4caSwyllys 	return (rv);
54299ebb4caSwyllys }
54399ebb4caSwyllys 
54499ebb4caSwyllys KMF_RETURN
PKCS_EncryptData(KMF_HANDLE_T kmfh,KMF_ALGORITHM_INDEX AlgorithmId,KMF_X509_SPKI * keyp,KMF_DATA * plaintext,KMF_DATA * ciphertext)54599ebb4caSwyllys PKCS_EncryptData(KMF_HANDLE_T kmfh,
54699ebb4caSwyllys 		KMF_ALGORITHM_INDEX AlgorithmId,
54799ebb4caSwyllys 		KMF_X509_SPKI *keyp,
54899ebb4caSwyllys 		KMF_DATA *plaintext,
54999ebb4caSwyllys 		KMF_DATA *ciphertext)
55099ebb4caSwyllys {
55199ebb4caSwyllys 	KMF_RETURN rv = KMF_OK;
55299ebb4caSwyllys 	CK_RV ckRv;
55399ebb4caSwyllys 	CK_MECHANISM ckMechanism;
554e65e5c2dSWyllys Ingersoll 	CK_MECHANISM_TYPE mechtype;
555e65e5c2dSWyllys Ingersoll 	CK_KEY_TYPE keytype;
556e65e5c2dSWyllys Ingersoll 	CK_OBJECT_HANDLE ckKeyHandle = 0;
557*f810c7e5SToomas Soome 	CK_SESSION_HANDLE ckSession = 0;
55899ebb4caSwyllys 	CK_ULONG out_len = 0, in_len = 0, total_encrypted = 0;
55999ebb4caSwyllys 	uint8_t *in_data, *out_data;
56099ebb4caSwyllys 	int i, blocks, block_size;
56199ebb4caSwyllys 	CK_ATTRIBUTE ckTemplate[2];
56299ebb4caSwyllys 	CK_ULONG ckNumTemplates;
56399ebb4caSwyllys 	CK_ULONG ckMaxTemplates = (sizeof (ckTemplate) /
56430a5e8faSwyllys 	    sizeof (CK_ATTRIBUTE));
56599ebb4caSwyllys 
566e65e5c2dSWyllys Ingersoll 	if (get_pk11_data(AlgorithmId, &keytype, &mechtype, NULL, 0))
56799ebb4caSwyllys 		return (KMF_ERR_BAD_ALGORITHM);
56899ebb4caSwyllys 
569e65e5c2dSWyllys Ingersoll 	rv = kmf_create_pk11_session(&ckSession, mechtype, CKF_ENCRYPT);
57099ebb4caSwyllys 	if (rv != KMF_OK)
57199ebb4caSwyllys 		return (rv);
57299ebb4caSwyllys 
57399ebb4caSwyllys 	/* Get the public key used in encryption */
57499ebb4caSwyllys 	rv = PKCS_AcquirePublicKeyHandle(ckSession, keyp,
575e65e5c2dSWyllys Ingersoll 	    keytype, &ckKeyHandle);
57699ebb4caSwyllys 
57799ebb4caSwyllys 	if (rv != KMF_OK) {
57899ebb4caSwyllys 		(void) C_CloseSession(ckSession);
57999ebb4caSwyllys 		return (rv);
58099ebb4caSwyllys 	}
58199ebb4caSwyllys 
58299ebb4caSwyllys 	/* Get the modulus length */
58399ebb4caSwyllys 	ckNumTemplates = 0;
58430a5e8faSwyllys 	if (!PKCS_AddTemplate(ckTemplate, &ckNumTemplates, ckMaxTemplates,
58530a5e8faSwyllys 	    CKA_MODULUS, (CK_BYTE *)NULL, sizeof (CK_ULONG))) {
586e65e5c2dSWyllys Ingersoll 		if (ckKeyHandle != 0)
58799ebb4caSwyllys 			(void) C_DestroyObject(ckSession, ckKeyHandle);
58899ebb4caSwyllys 		(void) C_CloseSession(ckSession);
58999ebb4caSwyllys 		return (KMF_ERR_INTERNAL);
59099ebb4caSwyllys 	}
59199ebb4caSwyllys 
59230a5e8faSwyllys 	ckRv = C_GetAttributeValue(ckSession, ckKeyHandle,
59330a5e8faSwyllys 	    ckTemplate, ckNumTemplates);
59499ebb4caSwyllys 
59599ebb4caSwyllys 	if (ckRv != CKR_OK) {
596e65e5c2dSWyllys Ingersoll 		if (ckKeyHandle != 0)
59799ebb4caSwyllys 			(void) C_DestroyObject(ckSession, ckKeyHandle);
59899ebb4caSwyllys 		kmfh->lasterr.kstype = KMF_KEYSTORE_PK11TOKEN;
59999ebb4caSwyllys 		kmfh->lasterr.errcode = ckRv;
60099ebb4caSwyllys 		(void) C_CloseSession(ckSession);
60199ebb4caSwyllys 		return (KMF_ERR_INTERNAL);
60299ebb4caSwyllys 	}
60399ebb4caSwyllys 	out_len = ckTemplate[0].ulValueLen;
60499ebb4caSwyllys 
60599ebb4caSwyllys 	if (out_len > ciphertext->Length) {
606e65e5c2dSWyllys Ingersoll 		if (ckKeyHandle != 0)
60799ebb4caSwyllys 			(void) C_DestroyObject(ckSession, ckKeyHandle);
60899ebb4caSwyllys 		(void) C_CloseSession(ckSession);
60999ebb4caSwyllys 		return (KMF_ERR_BUFFER_SIZE);
61099ebb4caSwyllys 	}
61199ebb4caSwyllys 
612e65e5c2dSWyllys Ingersoll 	ckMechanism.mechanism = mechtype;
61399ebb4caSwyllys 	ckMechanism.pParameter = NULL_PTR;
61499ebb4caSwyllys 	ckMechanism.ulParameterLen = 0;
61599ebb4caSwyllys 
61699ebb4caSwyllys 	/* Compute the fixed input data length for single-part encryption */
61799ebb4caSwyllys 	block_size = out_len - 11;
61899ebb4caSwyllys 
61999ebb4caSwyllys 	in_data = plaintext->Data;
62099ebb4caSwyllys 	out_data = ciphertext->Data;
62199ebb4caSwyllys 
62299ebb4caSwyllys 	blocks = plaintext->Length/block_size;
62399ebb4caSwyllys 
62499ebb4caSwyllys 	for (i = 0; i < blocks; i++) {
62599ebb4caSwyllys 		ckRv = C_EncryptInit(ckSession, &ckMechanism, ckKeyHandle);
62699ebb4caSwyllys 		if (ckRv != CKR_OK) {
627e65e5c2dSWyllys Ingersoll 			if (ckKeyHandle != 0)
62899ebb4caSwyllys 				(void) C_DestroyObject(ckSession, ckKeyHandle);
62999ebb4caSwyllys 			kmfh->lasterr.kstype = KMF_KEYSTORE_PK11TOKEN;
63099ebb4caSwyllys 			kmfh->lasterr.errcode = ckRv;
63199ebb4caSwyllys 			(void) C_CloseSession(ckSession);
63299ebb4caSwyllys 			return (KMF_ERR_INTERNAL);
63399ebb4caSwyllys 		}
63499ebb4caSwyllys 		ckRv = C_Encrypt(ckSession, (CK_BYTE_PTR)in_data, block_size,
63599ebb4caSwyllys 		    (CK_BYTE_PTR)out_data, &out_len);
63699ebb4caSwyllys 
63799ebb4caSwyllys 		if (ckRv != CKR_OK) {
638e65e5c2dSWyllys Ingersoll 			if (ckKeyHandle != 0)
63999ebb4caSwyllys 				(void) C_DestroyObject(ckSession, ckKeyHandle);
64099ebb4caSwyllys 			kmfh->lasterr.kstype = KMF_KEYSTORE_PK11TOKEN;
64199ebb4caSwyllys 			kmfh->lasterr.errcode = ckRv;
64299ebb4caSwyllys 			(void) C_CloseSession(ckSession);
64399ebb4caSwyllys 			return (KMF_ERR_INTERNAL);
64499ebb4caSwyllys 		}
64599ebb4caSwyllys 
64699ebb4caSwyllys 		out_data += out_len;
64799ebb4caSwyllys 		total_encrypted += out_len;
64899ebb4caSwyllys 		in_data += block_size;
64999ebb4caSwyllys 	}
65099ebb4caSwyllys 
65199ebb4caSwyllys 	if (plaintext->Length % block_size) {
65299ebb4caSwyllys 		/* Encrypt the remaining data */
65399ebb4caSwyllys 		ckRv = C_EncryptInit(ckSession, &ckMechanism, ckKeyHandle);
65499ebb4caSwyllys 		if (ckRv != CKR_OK) {
655e65e5c2dSWyllys Ingersoll 			if (ckKeyHandle != 0)
65699ebb4caSwyllys 				(void) C_DestroyObject(ckSession, ckKeyHandle);
65799ebb4caSwyllys 			kmfh->lasterr.kstype = KMF_KEYSTORE_PK11TOKEN;
65899ebb4caSwyllys 			kmfh->lasterr.errcode = ckRv;
65999ebb4caSwyllys 			(void) C_CloseSession(ckSession);
66099ebb4caSwyllys 			return (KMF_ERR_INTERNAL);
66199ebb4caSwyllys 		}
66299ebb4caSwyllys 
66399ebb4caSwyllys 		in_len = plaintext->Length % block_size;
66499ebb4caSwyllys 		ckRv = C_Encrypt(ckSession, (CK_BYTE_PTR)in_data, in_len,
66599ebb4caSwyllys 		    (CK_BYTE_PTR)out_data, &out_len);
66699ebb4caSwyllys 
66799ebb4caSwyllys 		if (ckRv != CKR_OK) {
668e65e5c2dSWyllys Ingersoll 			if (ckKeyHandle != 0)
66999ebb4caSwyllys 				(void) C_DestroyObject(ckSession, ckKeyHandle);
67099ebb4caSwyllys 			kmfh->lasterr.kstype = KMF_KEYSTORE_PK11TOKEN;
67199ebb4caSwyllys 			kmfh->lasterr.errcode = ckRv;
67299ebb4caSwyllys 			(void) C_CloseSession(ckSession);
67399ebb4caSwyllys 			return (KMF_ERR_INTERNAL);
67499ebb4caSwyllys 		}
67599ebb4caSwyllys 
67699ebb4caSwyllys 		out_data += out_len;
67799ebb4caSwyllys 		total_encrypted += out_len;
67899ebb4caSwyllys 		in_data += in_len;
67999ebb4caSwyllys 	}
68099ebb4caSwyllys 
68199ebb4caSwyllys 	ciphertext->Length = total_encrypted;
68299ebb4caSwyllys 
683e65e5c2dSWyllys Ingersoll 	if (ckKeyHandle != 0)
68499ebb4caSwyllys 		(void) C_DestroyObject(ckSession, ckKeyHandle);
68599ebb4caSwyllys 
68699ebb4caSwyllys 	(void) C_CloseSession(ckSession);
68799ebb4caSwyllys 	return (rv);
68899ebb4caSwyllys 
68999ebb4caSwyllys }
69099ebb4caSwyllys 
6919b37d296Swyllys static void
create_id_hash(KMF_DATA * IDInput,KMF_DATA * IDOutput)692e65e5c2dSWyllys Ingersoll create_id_hash(KMF_DATA *IDInput, KMF_DATA *IDOutput)
69399ebb4caSwyllys {
6949b37d296Swyllys 	SHA1_CTX ctx;
69599ebb4caSwyllys 
6969b37d296Swyllys 	SHA1Init(&ctx);
6979b37d296Swyllys 	SHA1Update(&ctx, IDInput->Data, IDInput->Length);
6989b37d296Swyllys 	SHA1Final(IDOutput->Data, &ctx);
69999ebb4caSwyllys 
7009b37d296Swyllys 	IDOutput->Length = SHA1_DIGEST_LENGTH;
70199ebb4caSwyllys }
70299ebb4caSwyllys 
70399ebb4caSwyllys KMF_RETURN
GetIDFromSPKI(KMF_X509_SPKI * spki,KMF_DATA * ID)7049b37d296Swyllys GetIDFromSPKI(KMF_X509_SPKI *spki, KMF_DATA *ID)
70599ebb4caSwyllys {
70699ebb4caSwyllys 	KMF_RETURN rv = KMF_OK;
70799ebb4caSwyllys 	KMF_DATA KeyParts[KMF_MAX_PUBLIC_KEY_PARTS];
70899ebb4caSwyllys 	uint32_t uNumKeyParts = KMF_MAX_PUBLIC_KEY_PARTS;
70999ebb4caSwyllys 	KMF_ALGORITHM_INDEX algId;
71099ebb4caSwyllys 	int i;
71199ebb4caSwyllys 
71299ebb4caSwyllys 	if (ID == NULL || spki == NULL)
71399ebb4caSwyllys 		return (KMF_ERR_BAD_PARAMETER);
71499ebb4caSwyllys 
71599ebb4caSwyllys 	ID->Data = (uchar_t *)malloc(SHA1_HASH_LENGTH);
71699ebb4caSwyllys 	if (ID->Data == NULL)
71799ebb4caSwyllys 		return (KMF_ERR_MEMORY);
71899ebb4caSwyllys 
71999ebb4caSwyllys 	ID->Length = SHA1_HASH_LENGTH;
72099ebb4caSwyllys 
72130a5e8faSwyllys 	algId = x509_algoid_to_algid(&spki->algorithm.algorithm);
72230a5e8faSwyllys 	if (algId == KMF_ALGID_NONE)
72330a5e8faSwyllys 		return (KMF_ERR_BAD_ALGORITHM);
72499ebb4caSwyllys 
72599ebb4caSwyllys 	rv = ExtractSPKIData(spki, algId, KeyParts, &uNumKeyParts);
72699ebb4caSwyllys 	if (rv != KMF_OK)
72799ebb4caSwyllys 		return (rv);
72899ebb4caSwyllys 
72999ebb4caSwyllys 	/* Check the KEY algorithm */
73099ebb4caSwyllys 	if (algId == KMF_ALGID_RSA) {
731e65e5c2dSWyllys Ingersoll 		create_id_hash(&KeyParts[KMF_RSA_MODULUS], ID);
73299ebb4caSwyllys 	} else if (algId == KMF_ALGID_DSA) {
733e65e5c2dSWyllys Ingersoll 		create_id_hash(&KeyParts[KMF_DSA_PUBLIC_VALUE], ID);
734e65e5c2dSWyllys Ingersoll 	} else if (algId == KMF_ALGID_SHA1WithECDSA ||
735e65e5c2dSWyllys Ingersoll 	    algId == KMF_ALGID_ECDSA) {
736e65e5c2dSWyllys Ingersoll 		create_id_hash(&KeyParts[KMF_ECDSA_POINT], ID);
73799ebb4caSwyllys 	} else {
73899ebb4caSwyllys 		/* We only support RSA and DSA keys for now */
73999ebb4caSwyllys 		rv = KMF_ERR_BAD_ALGORITHM;
74099ebb4caSwyllys 	}
74199ebb4caSwyllys 
74299ebb4caSwyllys 	for (i = 0; i < uNumKeyParts; i++) {
74399ebb4caSwyllys 		if (KeyParts[i].Data != NULL)
74499ebb4caSwyllys 			free(KeyParts[i].Data);
74599ebb4caSwyllys 	}
74699ebb4caSwyllys 
74799ebb4caSwyllys 	if (rv != KMF_OK && ID->Data != NULL) {
74899ebb4caSwyllys 		free(ID->Data);
74999ebb4caSwyllys 		ID->Data = NULL;
75099ebb4caSwyllys 		ID->Length = 0;
75199ebb4caSwyllys 	}
75299ebb4caSwyllys 
75399ebb4caSwyllys 	return (rv);
75499ebb4caSwyllys }
755e65e5c2dSWyllys Ingersoll 
756e65e5c2dSWyllys Ingersoll /*
757e65e5c2dSWyllys Ingersoll  * For PKCS1 encoding (necessary for RSA signatures), we
758e65e5c2dSWyllys Ingersoll  * must prepend the following prefixes before computing
759e65e5c2dSWyllys Ingersoll  * the digest.
760e65e5c2dSWyllys Ingersoll  */
761e65e5c2dSWyllys Ingersoll static uchar_t SHA1_DER_PREFIX[] = {
762e65e5c2dSWyllys Ingersoll 	0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e,
763e65e5c2dSWyllys Ingersoll 	0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14
764e65e5c2dSWyllys Ingersoll };
765e65e5c2dSWyllys Ingersoll static uchar_t MD5_DER_PREFIX[] = {
766e65e5c2dSWyllys Ingersoll 	0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86,
767e65e5c2dSWyllys Ingersoll 	0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05, 0x05, 0x00,
768e65e5c2dSWyllys Ingersoll 	0x04, 0x10
769e65e5c2dSWyllys Ingersoll };
770e65e5c2dSWyllys Ingersoll static uchar_t SHA256_DER_PREFIX[] = {0x30, 0x31, 0x30, 0x0d,
771e65e5c2dSWyllys Ingersoll     0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05,
772e65e5c2dSWyllys Ingersoll     0x00, 0x04, 0x20};
773e65e5c2dSWyllys Ingersoll 
774e65e5c2dSWyllys Ingersoll static uchar_t SHA384_DER_PREFIX[] = {0x30, 0x41, 0x30, 0x0d,
775e65e5c2dSWyllys Ingersoll     0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05,
776e65e5c2dSWyllys Ingersoll     0x00, 0x04, 0x30};
777e65e5c2dSWyllys Ingersoll 
778e65e5c2dSWyllys Ingersoll static uchar_t SHA512_DER_PREFIX[] = {0x30, 0x51, 0x30, 0x0d,
779e65e5c2dSWyllys Ingersoll     0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05,
780e65e5c2dSWyllys Ingersoll     0x00, 0x04, 0x40};
781e65e5c2dSWyllys Ingersoll 
782e65e5c2dSWyllys Ingersoll #define	MAX_SHA2_DIGEST_LENGTH 64
783e65e5c2dSWyllys Ingersoll /*
784e65e5c2dSWyllys Ingersoll  * Compute hashes using metaslot (or softtoken).
785e65e5c2dSWyllys Ingersoll  * Not all hardware tokens support the combined HASH + RSA/EC
786e65e5c2dSWyllys Ingersoll  * Signing operations so it is safer to separate the hashing
787e65e5c2dSWyllys Ingersoll  * from the signing.  This function generates a hash using a
788e65e5c2dSWyllys Ingersoll  * separate session.  The resulting digest can be signed later.
789e65e5c2dSWyllys Ingersoll  */
790e65e5c2dSWyllys Ingersoll KMF_RETURN
PKCS_DigestData(KMF_HANDLE_T handle,CK_SESSION_HANDLE hSession,CK_MECHANISM_TYPE mechtype,KMF_DATA * tobesigned,KMF_DATA * output,boolean_t pkcs1_encoding)791e65e5c2dSWyllys Ingersoll PKCS_DigestData(KMF_HANDLE_T handle,
792e65e5c2dSWyllys Ingersoll     CK_SESSION_HANDLE hSession,
793e65e5c2dSWyllys Ingersoll     CK_MECHANISM_TYPE mechtype,
794e65e5c2dSWyllys Ingersoll     KMF_DATA *tobesigned, KMF_DATA *output,
795e65e5c2dSWyllys Ingersoll     boolean_t pkcs1_encoding)
796e65e5c2dSWyllys Ingersoll {
797e65e5c2dSWyllys Ingersoll 	KMF_RETURN	rv = KMF_OK;
798e65e5c2dSWyllys Ingersoll 	CK_RV		ckrv;
799e65e5c2dSWyllys Ingersoll 	CK_MECHANISM	mechanism;
800e65e5c2dSWyllys Ingersoll 	KMF_HANDLE	*kmfh = (KMF_HANDLE *)handle;
801e65e5c2dSWyllys Ingersoll 	CK_BYTE		outbuf[MAX_SHA2_DIGEST_LENGTH +
802e65e5c2dSWyllys Ingersoll 	    sizeof (SHA512_DER_PREFIX)];
803e65e5c2dSWyllys Ingersoll 	CK_ULONG	outlen = sizeof (outbuf);
804e65e5c2dSWyllys Ingersoll 
805e65e5c2dSWyllys Ingersoll 	mechanism.mechanism = mechtype;
806e65e5c2dSWyllys Ingersoll 	mechanism.pParameter = NULL;
807e65e5c2dSWyllys Ingersoll 	mechanism.ulParameterLen = 0;
808e65e5c2dSWyllys Ingersoll 
809e65e5c2dSWyllys Ingersoll 	ckrv = C_DigestInit(hSession, &mechanism);
810e65e5c2dSWyllys Ingersoll 	if (ckrv != CKR_OK) {
811e65e5c2dSWyllys Ingersoll 		kmfh->lasterr.kstype = KMF_KEYSTORE_PK11TOKEN;
812e65e5c2dSWyllys Ingersoll 		kmfh->lasterr.errcode = ckrv;
813e65e5c2dSWyllys Ingersoll 		rv = KMF_ERR_INTERNAL;
814e65e5c2dSWyllys Ingersoll 		goto end;
815e65e5c2dSWyllys Ingersoll 	}
816e65e5c2dSWyllys Ingersoll 
817e65e5c2dSWyllys Ingersoll 	ckrv = C_Digest(hSession, tobesigned->Data,
818e65e5c2dSWyllys Ingersoll 	    tobesigned->Length, outbuf, &outlen);
819e65e5c2dSWyllys Ingersoll 	if (ckrv != CKR_OK) {
820e65e5c2dSWyllys Ingersoll 		kmfh->lasterr.kstype = KMF_KEYSTORE_PK11TOKEN;
821e65e5c2dSWyllys Ingersoll 		kmfh->lasterr.errcode = ckrv;
822e65e5c2dSWyllys Ingersoll 		rv = KMF_ERR_INTERNAL;
823e65e5c2dSWyllys Ingersoll 	}
824e65e5c2dSWyllys Ingersoll 
825e65e5c2dSWyllys Ingersoll 	if (pkcs1_encoding) {
826e65e5c2dSWyllys Ingersoll 		uchar_t *pfx;
827e65e5c2dSWyllys Ingersoll 		int pfxlen;
828e65e5c2dSWyllys Ingersoll 		switch (mechtype) {
829e65e5c2dSWyllys Ingersoll 			case CKM_MD5:
830e65e5c2dSWyllys Ingersoll 				pfx = MD5_DER_PREFIX;
831e65e5c2dSWyllys Ingersoll 				pfxlen = sizeof (MD5_DER_PREFIX);
832e65e5c2dSWyllys Ingersoll 				break;
833e65e5c2dSWyllys Ingersoll 			case CKM_SHA_1:
834e65e5c2dSWyllys Ingersoll 				pfx = SHA1_DER_PREFIX;
835e65e5c2dSWyllys Ingersoll 				pfxlen = sizeof (SHA1_DER_PREFIX);
836e65e5c2dSWyllys Ingersoll 				break;
837e65e5c2dSWyllys Ingersoll 			case CKM_SHA256:
838e65e5c2dSWyllys Ingersoll 				pfx = SHA256_DER_PREFIX;
839e65e5c2dSWyllys Ingersoll 				pfxlen = sizeof (SHA256_DER_PREFIX);
840e65e5c2dSWyllys Ingersoll 				break;
841e65e5c2dSWyllys Ingersoll 			case CKM_SHA384:
842e65e5c2dSWyllys Ingersoll 				pfx = SHA384_DER_PREFIX;
843e65e5c2dSWyllys Ingersoll 				pfxlen = sizeof (SHA384_DER_PREFIX);
844e65e5c2dSWyllys Ingersoll 				break;
845e65e5c2dSWyllys Ingersoll 			case CKM_SHA512:
846e65e5c2dSWyllys Ingersoll 				pfx = SHA512_DER_PREFIX;
847e65e5c2dSWyllys Ingersoll 				pfxlen = sizeof (SHA512_DER_PREFIX);
848e65e5c2dSWyllys Ingersoll 				break;
849e65e5c2dSWyllys Ingersoll 			default:
850e65e5c2dSWyllys Ingersoll 				rv = KMF_ERR_BAD_ALGORITHM;
851e65e5c2dSWyllys Ingersoll 				goto end;
852e65e5c2dSWyllys Ingersoll 		}
853e65e5c2dSWyllys Ingersoll 		(void) memcpy(output->Data, pfx, pfxlen);
854e65e5c2dSWyllys Ingersoll 		(void) memcpy(output->Data + pfxlen, outbuf, outlen);
855e65e5c2dSWyllys Ingersoll 		output->Length = outlen + pfxlen;
856e65e5c2dSWyllys Ingersoll 	} else {
857e65e5c2dSWyllys Ingersoll 		(void) memcpy(output->Data, outbuf, outlen);
858e65e5c2dSWyllys Ingersoll 		output->Length = outlen;
859e65e5c2dSWyllys Ingersoll 	}
860e65e5c2dSWyllys Ingersoll 
861e65e5c2dSWyllys Ingersoll end:
862e65e5c2dSWyllys Ingersoll 	return (rv);
863e65e5c2dSWyllys Ingersoll }
864