xref: /illumos-gate/usr/src/lib/pkcs11/pkcs11_tpm/common/tpm_specific.c (revision 1dc1cb45bfad586798535d0037f852b3976f4e99)
147e946e7SWyllys Ingersoll /*
247e946e7SWyllys Ingersoll  * The Initial Developer of the Original Code is International
347e946e7SWyllys Ingersoll  * Business Machines Corporation. Portions created by IBM
447e946e7SWyllys Ingersoll  * Corporation are Copyright (C) 2005 International Business
547e946e7SWyllys Ingersoll  * Machines Corporation. All Rights Reserved.
647e946e7SWyllys Ingersoll  *
747e946e7SWyllys Ingersoll  * This program is free software; you can redistribute it and/or modify
847e946e7SWyllys Ingersoll  * it under the terms of the Common Public License as published by
947e946e7SWyllys Ingersoll  * IBM Corporation; either version 1 of the License, or (at your option)
1047e946e7SWyllys Ingersoll  * any later version.
1147e946e7SWyllys Ingersoll  *
1247e946e7SWyllys Ingersoll  * This program is distributed in the hope that it will be useful,
1347e946e7SWyllys Ingersoll  * but WITHOUT ANY WARRANTY; without even the implied warranty of
1447e946e7SWyllys Ingersoll  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1547e946e7SWyllys Ingersoll  * Common Public License for more details.
1647e946e7SWyllys Ingersoll  *
1747e946e7SWyllys Ingersoll  * You should have received a copy of the Common Public License
1847e946e7SWyllys Ingersoll  * along with this program; if not, a copy can be viewed at
1947e946e7SWyllys Ingersoll  * http://www.opensource.org/licenses/cpl1.0.php.
2047e946e7SWyllys Ingersoll  */
2147e946e7SWyllys Ingersoll /*
2247e946e7SWyllys Ingersoll  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
2347e946e7SWyllys Ingersoll  * Use is subject to license terms.
2447e946e7SWyllys Ingersoll  */
2547e946e7SWyllys Ingersoll 
2647e946e7SWyllys Ingersoll #include <pthread.h>
2747e946e7SWyllys Ingersoll #include <string.h>
2847e946e7SWyllys Ingersoll 
2947e946e7SWyllys Ingersoll #include <sys/types.h>
3047e946e7SWyllys Ingersoll #include <sys/stat.h>
3147e946e7SWyllys Ingersoll #include <uuid/uuid.h>
3247e946e7SWyllys Ingersoll #include <fcntl.h>
3347e946e7SWyllys Ingersoll #include <errno.h>
3447e946e7SWyllys Ingersoll #include <pwd.h>
3547e946e7SWyllys Ingersoll #include <syslog.h>
3647e946e7SWyllys Ingersoll 
37ab8176c2SWyllys Ingersoll #include <openssl/rsa.h>
38ab8176c2SWyllys Ingersoll 
3947e946e7SWyllys Ingersoll #include <tss/platform.h>
4047e946e7SWyllys Ingersoll #include <tss/tss_defines.h>
4147e946e7SWyllys Ingersoll #include <tss/tss_typedef.h>
4247e946e7SWyllys Ingersoll #include <tss/tss_structs.h>
4347e946e7SWyllys Ingersoll #include <tss/tss_error.h>
4447e946e7SWyllys Ingersoll #include <tss/tcs_error.h>
4547e946e7SWyllys Ingersoll #include <tss/tspi.h>
4647e946e7SWyllys Ingersoll #include <trousers/trousers.h>
4747e946e7SWyllys Ingersoll 
4847e946e7SWyllys Ingersoll #include "tpmtok_int.h"
4947e946e7SWyllys Ingersoll #include "tpmtok_defs.h"
5047e946e7SWyllys Ingersoll 
51ab8176c2SWyllys Ingersoll #define	MAX_RSA_KEYLENGTH 512
52ab8176c2SWyllys Ingersoll 
5347e946e7SWyllys Ingersoll extern void stlogit(char *fmt, ...);
5447e946e7SWyllys Ingersoll 
5547e946e7SWyllys Ingersoll CK_RV token_rng(TSS_HCONTEXT, CK_BYTE *,  CK_ULONG);
5647e946e7SWyllys Ingersoll int tok_slot2local(CK_SLOT_ID);
5747e946e7SWyllys Ingersoll CK_RV token_specific_session(CK_SLOT_ID);
58ab8176c2SWyllys Ingersoll CK_RV token_specific_final(TSS_HCONTEXT);
5947e946e7SWyllys Ingersoll 
6047e946e7SWyllys Ingersoll CK_RV
6147e946e7SWyllys Ingersoll token_specific_rsa_decrypt(
6247e946e7SWyllys Ingersoll 	TSS_HCONTEXT,
6347e946e7SWyllys Ingersoll 	CK_BYTE *,
6447e946e7SWyllys Ingersoll 	CK_ULONG,
6547e946e7SWyllys Ingersoll 	CK_BYTE *,
6647e946e7SWyllys Ingersoll 	CK_ULONG *,
6747e946e7SWyllys Ingersoll 	OBJECT *);
6847e946e7SWyllys Ingersoll 
6947e946e7SWyllys Ingersoll CK_RV
7047e946e7SWyllys Ingersoll token_specific_rsa_encrypt(
7147e946e7SWyllys Ingersoll 	TSS_HCONTEXT,
7247e946e7SWyllys Ingersoll 	CK_BYTE *,
7347e946e7SWyllys Ingersoll 	CK_ULONG,
7447e946e7SWyllys Ingersoll 	CK_BYTE *,
7547e946e7SWyllys Ingersoll 	CK_ULONG *,
7647e946e7SWyllys Ingersoll 	OBJECT *);
7747e946e7SWyllys Ingersoll 
7847e946e7SWyllys Ingersoll CK_RV
7947e946e7SWyllys Ingersoll token_specific_rsa_sign(
8047e946e7SWyllys Ingersoll 	TSS_HCONTEXT,
8147e946e7SWyllys Ingersoll 	CK_BYTE *,
8247e946e7SWyllys Ingersoll 	CK_ULONG,
8347e946e7SWyllys Ingersoll 	CK_BYTE *,
8447e946e7SWyllys Ingersoll 	CK_ULONG *,
8547e946e7SWyllys Ingersoll 	OBJECT *);
8647e946e7SWyllys Ingersoll 
8747e946e7SWyllys Ingersoll CK_RV
8847e946e7SWyllys Ingersoll token_specific_rsa_verify(TSS_HCONTEXT, CK_BYTE *,
8947e946e7SWyllys Ingersoll     CK_ULONG, CK_BYTE *, CK_ULONG, OBJECT *);
9047e946e7SWyllys Ingersoll 
9147e946e7SWyllys Ingersoll CK_RV
9247e946e7SWyllys Ingersoll token_specific_rsa_generate_keypair(TSS_HCONTEXT,
9347e946e7SWyllys Ingersoll 	TEMPLATE *,
9447e946e7SWyllys Ingersoll 	TEMPLATE *);
9547e946e7SWyllys Ingersoll 
9647e946e7SWyllys Ingersoll CK_RV
9747e946e7SWyllys Ingersoll token_specific_sha_init(DIGEST_CONTEXT *);
9847e946e7SWyllys Ingersoll 
9947e946e7SWyllys Ingersoll CK_RV
10047e946e7SWyllys Ingersoll token_specific_sha_update(DIGEST_CONTEXT *,
10147e946e7SWyllys Ingersoll 	CK_BYTE *,
10247e946e7SWyllys Ingersoll 	CK_ULONG);
10347e946e7SWyllys Ingersoll 
10447e946e7SWyllys Ingersoll CK_RV
10547e946e7SWyllys Ingersoll token_specific_sha_final(DIGEST_CONTEXT *,
10647e946e7SWyllys Ingersoll 	CK_BYTE *,
10747e946e7SWyllys Ingersoll 	CK_ULONG *);
10847e946e7SWyllys Ingersoll 
10947e946e7SWyllys Ingersoll CK_RV token_specific_login(TSS_HCONTEXT, CK_USER_TYPE, CK_CHAR_PTR, CK_ULONG);
11047e946e7SWyllys Ingersoll CK_RV token_specific_logout(TSS_HCONTEXT);
11147e946e7SWyllys Ingersoll CK_RV token_specific_init_pin(TSS_HCONTEXT, CK_CHAR_PTR, CK_ULONG);
11247e946e7SWyllys Ingersoll CK_RV token_specific_set_pin(ST_SESSION_HANDLE, CK_CHAR_PTR,
11347e946e7SWyllys Ingersoll 	CK_ULONG, CK_CHAR_PTR, CK_ULONG);
11447e946e7SWyllys Ingersoll CK_RV token_specific_verify_so_pin(TSS_HCONTEXT, CK_CHAR_PTR, CK_ULONG);
11547e946e7SWyllys Ingersoll 
11647e946e7SWyllys Ingersoll static CK_RV
11747e946e7SWyllys Ingersoll token_specific_init(char *, CK_SLOT_ID, TSS_HCONTEXT *);
11847e946e7SWyllys Ingersoll 
11947e946e7SWyllys Ingersoll struct token_specific_struct token_specific = {
12047e946e7SWyllys Ingersoll 	"TPM_Debug",
12147e946e7SWyllys Ingersoll 	&token_specific_init,
12247e946e7SWyllys Ingersoll 	NULL,
12347e946e7SWyllys Ingersoll 	&token_rng,
12447e946e7SWyllys Ingersoll 	&token_specific_session,
12547e946e7SWyllys Ingersoll 	&token_specific_final,
12647e946e7SWyllys Ingersoll 	&token_specific_rsa_decrypt,
12747e946e7SWyllys Ingersoll 	&token_specific_rsa_encrypt,
12847e946e7SWyllys Ingersoll 	&token_specific_rsa_sign,
12947e946e7SWyllys Ingersoll 	&token_specific_rsa_verify,
13047e946e7SWyllys Ingersoll 	&token_specific_rsa_generate_keypair,
13147e946e7SWyllys Ingersoll 	NULL,
13247e946e7SWyllys Ingersoll 	NULL,
13347e946e7SWyllys Ingersoll 	NULL,
13447e946e7SWyllys Ingersoll 	&token_specific_login,
13547e946e7SWyllys Ingersoll 	&token_specific_logout,
13647e946e7SWyllys Ingersoll 	&token_specific_init_pin,
13747e946e7SWyllys Ingersoll 	&token_specific_set_pin,
13847e946e7SWyllys Ingersoll 	&token_specific_verify_so_pin
13947e946e7SWyllys Ingersoll };
14047e946e7SWyllys Ingersoll 
14147e946e7SWyllys Ingersoll /* The context we'll use globally to connect to the TSP */
14247e946e7SWyllys Ingersoll 
14347e946e7SWyllys Ingersoll /* TSP key handles */
14447e946e7SWyllys Ingersoll TSS_HKEY hPublicRootKey = NULL_HKEY;
14547e946e7SWyllys Ingersoll TSS_HKEY hPublicLeafKey = NULL_HKEY;
14647e946e7SWyllys Ingersoll TSS_HKEY hPrivateRootKey = NULL_HKEY;
14747e946e7SWyllys Ingersoll TSS_HKEY hPrivateLeafKey = NULL_HKEY;
14847e946e7SWyllys Ingersoll 
14947e946e7SWyllys Ingersoll TSS_UUID publicRootKeyUUID;
15047e946e7SWyllys Ingersoll TSS_UUID publicLeafKeyUUID;
15147e946e7SWyllys Ingersoll TSS_UUID privateRootKeyUUID;
15247e946e7SWyllys Ingersoll TSS_UUID privateLeafKeyUUID;
15347e946e7SWyllys Ingersoll 
15447e946e7SWyllys Ingersoll /* TSP policy handles */
15547e946e7SWyllys Ingersoll TSS_HPOLICY hDefaultPolicy = NULL_HPOLICY;
15647e946e7SWyllys Ingersoll 
15747e946e7SWyllys Ingersoll /* PKCS#11 key handles */
15847e946e7SWyllys Ingersoll int not_initialized = 0;
15947e946e7SWyllys Ingersoll 
16047e946e7SWyllys Ingersoll CK_BYTE current_user_pin_sha[SHA1_DIGEST_LENGTH];
16147e946e7SWyllys Ingersoll CK_BYTE current_so_pin_sha[SHA1_DIGEST_LENGTH];
16247e946e7SWyllys Ingersoll 
16347e946e7SWyllys Ingersoll static TPM_CAP_VERSION_INFO tpmvinfo;
16447e946e7SWyllys Ingersoll 
16547e946e7SWyllys Ingersoll static CK_RV
16647e946e7SWyllys Ingersoll verify_user_pin(TSS_HCONTEXT, CK_BYTE *);
16747e946e7SWyllys Ingersoll 
168ab8176c2SWyllys Ingersoll static TSS_RESULT
169ab8176c2SWyllys Ingersoll tss_assign_secret_key_policy(TSS_HCONTEXT, TSS_FLAG, TSS_HKEY, CK_CHAR *);
170ab8176c2SWyllys Ingersoll 
171ab8176c2SWyllys Ingersoll static TSS_RESULT
172ab8176c2SWyllys Ingersoll set_legacy_key_params(TSS_HKEY);
173ab8176c2SWyllys Ingersoll 
17447e946e7SWyllys Ingersoll static void
17547e946e7SWyllys Ingersoll local_uuid_clear(TSS_UUID *uuid)
17647e946e7SWyllys Ingersoll {
17747e946e7SWyllys Ingersoll 	if (uuid == NULL)
17847e946e7SWyllys Ingersoll 		return;
17947e946e7SWyllys Ingersoll 	(void) memset(uuid, 0, sizeof (TSS_UUID));
18047e946e7SWyllys Ingersoll }
18147e946e7SWyllys Ingersoll 
18247e946e7SWyllys Ingersoll 
18347e946e7SWyllys Ingersoll /* convert from TSS_UUID to uuid_t */
18447e946e7SWyllys Ingersoll static void
18547e946e7SWyllys Ingersoll tss_uuid_convert_from(TSS_UUID *uu, uuid_t ptr)
18647e946e7SWyllys Ingersoll {
18747e946e7SWyllys Ingersoll 	uint_t		tmp;
18847e946e7SWyllys Ingersoll 	uchar_t		*out = ptr;
18947e946e7SWyllys Ingersoll 
19047e946e7SWyllys Ingersoll 	tmp = ntohl(uu->ulTimeLow);
19147e946e7SWyllys Ingersoll 	out[3] = (uchar_t)tmp;
19247e946e7SWyllys Ingersoll 	tmp >>= 8;
19347e946e7SWyllys Ingersoll 	out[2] = (uchar_t)tmp;
19447e946e7SWyllys Ingersoll 	tmp >>= 8;
19547e946e7SWyllys Ingersoll 	out[1] = (uchar_t)tmp;
19647e946e7SWyllys Ingersoll 	tmp >>= 8;
19747e946e7SWyllys Ingersoll 	out[0] = (uchar_t)tmp;
19847e946e7SWyllys Ingersoll 
19947e946e7SWyllys Ingersoll 	tmp = ntohs(uu->usTimeMid);
20047e946e7SWyllys Ingersoll 	out[5] = (uchar_t)tmp;
20147e946e7SWyllys Ingersoll 	tmp >>= 8;
20247e946e7SWyllys Ingersoll 	out[4] = (uchar_t)tmp;
20347e946e7SWyllys Ingersoll 
20447e946e7SWyllys Ingersoll 	tmp = ntohs(uu->usTimeHigh);
20547e946e7SWyllys Ingersoll 	out[7] = (uchar_t)tmp;
20647e946e7SWyllys Ingersoll 	tmp >>= 8;
20747e946e7SWyllys Ingersoll 	out[6] = (uchar_t)tmp;
20847e946e7SWyllys Ingersoll 
20947e946e7SWyllys Ingersoll 	tmp = uu->bClockSeqHigh;
21047e946e7SWyllys Ingersoll 	out[8] = (uchar_t)tmp;
21147e946e7SWyllys Ingersoll 	tmp = uu->bClockSeqLow;
21247e946e7SWyllys Ingersoll 	out[9] = (uchar_t)tmp;
21347e946e7SWyllys Ingersoll 
21447e946e7SWyllys Ingersoll 	(void) memcpy(out+10, uu->rgbNode, 6);
21547e946e7SWyllys Ingersoll }
21647e946e7SWyllys Ingersoll 
21747e946e7SWyllys Ingersoll /* convert from uuid_t to TSS_UUID */
21847e946e7SWyllys Ingersoll static void
21947e946e7SWyllys Ingersoll tss_uuid_convert_to(TSS_UUID *uuid, uuid_t in)
22047e946e7SWyllys Ingersoll {
22147e946e7SWyllys Ingersoll 	uchar_t		*ptr;
22247e946e7SWyllys Ingersoll 	uint32_t	ltmp;
22347e946e7SWyllys Ingersoll 	uint16_t	stmp;
22447e946e7SWyllys Ingersoll 
22547e946e7SWyllys Ingersoll 	ptr = in;
22647e946e7SWyllys Ingersoll 
22747e946e7SWyllys Ingersoll 	ltmp = *ptr++;
22847e946e7SWyllys Ingersoll 	ltmp = (ltmp << 8) | *ptr++;
22947e946e7SWyllys Ingersoll 	ltmp = (ltmp << 8) | *ptr++;
23047e946e7SWyllys Ingersoll 	ltmp = (ltmp << 8) | *ptr++;
23147e946e7SWyllys Ingersoll 	uuid->ulTimeLow = ntohl(ltmp);
23247e946e7SWyllys Ingersoll 
23347e946e7SWyllys Ingersoll 	stmp = *ptr++;
23447e946e7SWyllys Ingersoll 	stmp = (stmp << 8) | *ptr++;
23547e946e7SWyllys Ingersoll 	uuid->usTimeMid = ntohs(stmp);
23647e946e7SWyllys Ingersoll 
23747e946e7SWyllys Ingersoll 	stmp = *ptr++;
23847e946e7SWyllys Ingersoll 	stmp = (stmp << 8) | *ptr++;
23947e946e7SWyllys Ingersoll 	uuid->usTimeHigh = ntohs(stmp);
24047e946e7SWyllys Ingersoll 
24147e946e7SWyllys Ingersoll 	uuid->bClockSeqHigh = *ptr++;
24247e946e7SWyllys Ingersoll 
24347e946e7SWyllys Ingersoll 	uuid->bClockSeqLow = *ptr++;
24447e946e7SWyllys Ingersoll 
24547e946e7SWyllys Ingersoll 	(void) memcpy(uuid->rgbNode, ptr, 6);
24647e946e7SWyllys Ingersoll }
24747e946e7SWyllys Ingersoll 
24847e946e7SWyllys Ingersoll static void
24947e946e7SWyllys Ingersoll local_uuid_copy(TSS_UUID *dst, TSS_UUID *src)
25047e946e7SWyllys Ingersoll {
25147e946e7SWyllys Ingersoll 	uuid_t udst, usrc;
25247e946e7SWyllys Ingersoll 
25347e946e7SWyllys Ingersoll 	tss_uuid_convert_from(dst, udst);
25447e946e7SWyllys Ingersoll 	tss_uuid_convert_from(src, usrc);
25547e946e7SWyllys Ingersoll 
25647e946e7SWyllys Ingersoll 	uuid_copy(udst, usrc);
25747e946e7SWyllys Ingersoll 
25847e946e7SWyllys Ingersoll 	tss_uuid_convert_to(dst, udst);
25947e946e7SWyllys Ingersoll }
26047e946e7SWyllys Ingersoll 
26147e946e7SWyllys Ingersoll static void
26247e946e7SWyllys Ingersoll local_uuid_generate(TSS_UUID *uu)
26347e946e7SWyllys Ingersoll {
26447e946e7SWyllys Ingersoll 	uuid_t newuuid;
26547e946e7SWyllys Ingersoll 
26647e946e7SWyllys Ingersoll 	uuid_generate(newuuid);
26747e946e7SWyllys Ingersoll 
26847e946e7SWyllys Ingersoll 	tss_uuid_convert_to(uu, newuuid);
26947e946e7SWyllys Ingersoll }
27047e946e7SWyllys Ingersoll 
27147e946e7SWyllys Ingersoll static int
27247e946e7SWyllys Ingersoll local_copy_file(char *dst, char *src)
27347e946e7SWyllys Ingersoll {
27447e946e7SWyllys Ingersoll 	FILE *fdest, *fsrc;
27547e946e7SWyllys Ingersoll 	char line[BUFSIZ];
27647e946e7SWyllys Ingersoll 
27747e946e7SWyllys Ingersoll 	fdest = fopen(dst, "w");
27847e946e7SWyllys Ingersoll 	if (fdest == NULL)
27947e946e7SWyllys Ingersoll 		return (-1);
28047e946e7SWyllys Ingersoll 
28147e946e7SWyllys Ingersoll 	fsrc = fopen(src, "r");
28247e946e7SWyllys Ingersoll 	if (fsrc == NULL) {
28347e946e7SWyllys Ingersoll 		(void) fclose(fdest);
28447e946e7SWyllys Ingersoll 		return (-1);
28547e946e7SWyllys Ingersoll 	}
28647e946e7SWyllys Ingersoll 
28747e946e7SWyllys Ingersoll 	while (fread(line, sizeof (line), 1, fsrc))
28847e946e7SWyllys Ingersoll 		(void) fprintf(fdest, "%s\n", line);
28947e946e7SWyllys Ingersoll 	(void) fclose(fsrc);
29047e946e7SWyllys Ingersoll 	(void) fclose(fdest);
29147e946e7SWyllys Ingersoll 	return (0);
29247e946e7SWyllys Ingersoll }
29347e946e7SWyllys Ingersoll 
29447e946e7SWyllys Ingersoll static int
29547e946e7SWyllys Ingersoll remove_uuid(char *keyname)
29647e946e7SWyllys Ingersoll {
29747e946e7SWyllys Ingersoll 	int ret = 0;
29847e946e7SWyllys Ingersoll 	FILE *fp, *newfp;
29947e946e7SWyllys Ingersoll 	char fname[MAXPATHLEN];
30047e946e7SWyllys Ingersoll 	char line[BUFSIZ], key[BUFSIZ], idstr[BUFSIZ];
30147e946e7SWyllys Ingersoll 	char *tmpfname;
30247e946e7SWyllys Ingersoll 	char *p = get_tpm_keystore_path();
30347e946e7SWyllys Ingersoll 
30447e946e7SWyllys Ingersoll 	if (p == NULL)
30547e946e7SWyllys Ingersoll 		return (-1);
30647e946e7SWyllys Ingersoll 
30747e946e7SWyllys Ingersoll 	(void) snprintf(fname, sizeof (fname),
30847e946e7SWyllys Ingersoll 	    "%s/%s", p, TPMTOK_UUID_INDEX_FILENAME);
30947e946e7SWyllys Ingersoll 
31047e946e7SWyllys Ingersoll 	fp = fopen(fname, "r");
31147e946e7SWyllys Ingersoll 	if (fp == NULL) {
31247e946e7SWyllys Ingersoll 		return (-1);
31347e946e7SWyllys Ingersoll 	}
31447e946e7SWyllys Ingersoll 
31547e946e7SWyllys Ingersoll 	tmpfname = tempnam("/tmp", "tpmtok");
31647e946e7SWyllys Ingersoll 	newfp = fopen(tmpfname, "w+");
31747e946e7SWyllys Ingersoll 	if (newfp == NULL) {
31847e946e7SWyllys Ingersoll 		free(tmpfname);
31947e946e7SWyllys Ingersoll 		(void) fclose(fp);
32047e946e7SWyllys Ingersoll 		return (-1);
32147e946e7SWyllys Ingersoll 	}
32247e946e7SWyllys Ingersoll 
32347e946e7SWyllys Ingersoll 	while (!feof(fp)) {
32447e946e7SWyllys Ingersoll 		(void) fgets(line, sizeof (line), fp);
32547e946e7SWyllys Ingersoll 		if (sscanf(line, "%1024s %1024s", key, idstr) == 2) {
32647e946e7SWyllys Ingersoll 			if (strcmp(key, keyname))
32747e946e7SWyllys Ingersoll 				(void) fprintf(newfp, "%s\n", line);
32847e946e7SWyllys Ingersoll 		}
32947e946e7SWyllys Ingersoll 	}
33047e946e7SWyllys Ingersoll 
33147e946e7SWyllys Ingersoll 	(void) fclose(fp);
33247e946e7SWyllys Ingersoll 	(void) fclose(newfp);
33347e946e7SWyllys Ingersoll 	if (local_copy_file(fname, tmpfname) == 0)
33447e946e7SWyllys Ingersoll 		(void) unlink(tmpfname);
33547e946e7SWyllys Ingersoll 
33647e946e7SWyllys Ingersoll 	free(tmpfname);
33747e946e7SWyllys Ingersoll 
33847e946e7SWyllys Ingersoll 	return (ret);
33947e946e7SWyllys Ingersoll }
34047e946e7SWyllys Ingersoll 
34147e946e7SWyllys Ingersoll static int
34247e946e7SWyllys Ingersoll find_uuid(char *keyname, TSS_UUID *uu)
34347e946e7SWyllys Ingersoll {
34447e946e7SWyllys Ingersoll 	int ret = 0, found = 0;
34547e946e7SWyllys Ingersoll 	FILE *fp = NULL;
34647e946e7SWyllys Ingersoll 	char fname[MAXPATHLEN];
34747e946e7SWyllys Ingersoll 	char line[BUFSIZ], key[BUFSIZ], idstr[BUFSIZ];
34847e946e7SWyllys Ingersoll 	uuid_t uuid;
34947e946e7SWyllys Ingersoll 	char *p = get_tpm_keystore_path();
35047e946e7SWyllys Ingersoll 
35147e946e7SWyllys Ingersoll 	if (p == NULL)
35247e946e7SWyllys Ingersoll 		return (-1);
35347e946e7SWyllys Ingersoll 
35447e946e7SWyllys Ingersoll 	tss_uuid_convert_from(uu, uuid);
35547e946e7SWyllys Ingersoll 
35647e946e7SWyllys Ingersoll 	(void) snprintf(fname, sizeof (fname),
35747e946e7SWyllys Ingersoll 	    "%s/%s", p, TPMTOK_UUID_INDEX_FILENAME);
35847e946e7SWyllys Ingersoll 
35947e946e7SWyllys Ingersoll 	/* Open UUID Index file */
36047e946e7SWyllys Ingersoll 	fp = fopen(fname, "r");
36147e946e7SWyllys Ingersoll 	if (fp == NULL) {
36247e946e7SWyllys Ingersoll 		if (errno == ENOENT) {
36347e946e7SWyllys Ingersoll 			/* initialize the file */
36447e946e7SWyllys Ingersoll 			fp = fopen(fname, "w");
36547e946e7SWyllys Ingersoll 			if (fp != NULL)
36647e946e7SWyllys Ingersoll 				(void) fclose(fp);
36747e946e7SWyllys Ingersoll 		}
36847e946e7SWyllys Ingersoll 		return (-1);
36947e946e7SWyllys Ingersoll 	}
37047e946e7SWyllys Ingersoll 
37147e946e7SWyllys Ingersoll 	while (!feof(fp)) {
37247e946e7SWyllys Ingersoll 		(void) fgets(line, sizeof (line), fp);
37347e946e7SWyllys Ingersoll 		if (sscanf(line, "%1024s %1024s", key, idstr) == 2) {
37447e946e7SWyllys Ingersoll 			if (strcmp(key, keyname) == 0) {
37547e946e7SWyllys Ingersoll 				ret = uuid_parse(idstr, uuid);
37647e946e7SWyllys Ingersoll 				if (ret == 0) {
37747e946e7SWyllys Ingersoll 					found = 1;
37847e946e7SWyllys Ingersoll 					tss_uuid_convert_to(uu,
37947e946e7SWyllys Ingersoll 					    uuid);
38047e946e7SWyllys Ingersoll 				}
38147e946e7SWyllys Ingersoll 				break;
38247e946e7SWyllys Ingersoll 			}
38347e946e7SWyllys Ingersoll 		}
38447e946e7SWyllys Ingersoll 	}
38547e946e7SWyllys Ingersoll 	(void) fclose(fp);
38647e946e7SWyllys Ingersoll 
38747e946e7SWyllys Ingersoll 	if (!found)
38847e946e7SWyllys Ingersoll 		ret = -1;
38947e946e7SWyllys Ingersoll 	return (ret);
39047e946e7SWyllys Ingersoll }
39147e946e7SWyllys Ingersoll 
39247e946e7SWyllys Ingersoll static int
39347e946e7SWyllys Ingersoll local_uuid_is_null(TSS_UUID *uu)
39447e946e7SWyllys Ingersoll {
39547e946e7SWyllys Ingersoll 	uuid_t uuid;
39647e946e7SWyllys Ingersoll 	int nulluuid;
39747e946e7SWyllys Ingersoll 
39847e946e7SWyllys Ingersoll 	tss_uuid_convert_from(uu, uuid);
39947e946e7SWyllys Ingersoll 
40047e946e7SWyllys Ingersoll 	nulluuid = uuid_is_null(uuid);
40147e946e7SWyllys Ingersoll 	return (nulluuid);
40247e946e7SWyllys Ingersoll }
40347e946e7SWyllys Ingersoll 
40447e946e7SWyllys Ingersoll static int
40547e946e7SWyllys Ingersoll add_uuid(char *keyname, TSS_UUID *uu)
40647e946e7SWyllys Ingersoll {
40747e946e7SWyllys Ingersoll 	FILE *fp = NULL;
40847e946e7SWyllys Ingersoll 	char fname[MAXPATHLEN];
40947e946e7SWyllys Ingersoll 	char idstr[BUFSIZ];
41047e946e7SWyllys Ingersoll 	uuid_t uuid;
41147e946e7SWyllys Ingersoll 	char *p = get_tpm_keystore_path();
41247e946e7SWyllys Ingersoll 
41347e946e7SWyllys Ingersoll 	if (p == NULL)
41447e946e7SWyllys Ingersoll 		return (-1);
41547e946e7SWyllys Ingersoll 
41647e946e7SWyllys Ingersoll 	tss_uuid_convert_from(uu, uuid);
41747e946e7SWyllys Ingersoll 
41847e946e7SWyllys Ingersoll 	if (uuid_is_null(uuid))
41947e946e7SWyllys Ingersoll 		return (-1);
42047e946e7SWyllys Ingersoll 
42147e946e7SWyllys Ingersoll 	uuid_unparse(uuid, idstr);
42247e946e7SWyllys Ingersoll 
42347e946e7SWyllys Ingersoll 	(void) snprintf(fname, sizeof (fname),
42447e946e7SWyllys Ingersoll 	    "%s/%s", p, TPMTOK_UUID_INDEX_FILENAME);
42547e946e7SWyllys Ingersoll 
42647e946e7SWyllys Ingersoll 	fp = fopen(fname, "a");
42747e946e7SWyllys Ingersoll 	if (fp == NULL)
42847e946e7SWyllys Ingersoll 		return (-1);
42947e946e7SWyllys Ingersoll 
43047e946e7SWyllys Ingersoll 	(void) fprintf(fp, "%s %s\n", keyname, idstr);
43147e946e7SWyllys Ingersoll 	(void) fclose(fp);
43247e946e7SWyllys Ingersoll 
43347e946e7SWyllys Ingersoll 	return (0);
43447e946e7SWyllys Ingersoll }
43547e946e7SWyllys Ingersoll 
43647e946e7SWyllys Ingersoll 
43747e946e7SWyllys Ingersoll static UINT32
43847e946e7SWyllys Ingersoll util_get_keysize_flag(CK_ULONG size)
43947e946e7SWyllys Ingersoll {
44047e946e7SWyllys Ingersoll 	switch (size) {
44147e946e7SWyllys Ingersoll 		case 512:
44247e946e7SWyllys Ingersoll 			return (TSS_KEY_SIZE_512);
44347e946e7SWyllys Ingersoll 			break;
44447e946e7SWyllys Ingersoll 		case 1024:
44547e946e7SWyllys Ingersoll 			return (TSS_KEY_SIZE_1024);
44647e946e7SWyllys Ingersoll 			break;
44747e946e7SWyllys Ingersoll 		case 2048:
44847e946e7SWyllys Ingersoll 			return (TSS_KEY_SIZE_2048);
44947e946e7SWyllys Ingersoll 			break;
45047e946e7SWyllys Ingersoll 		default:
45147e946e7SWyllys Ingersoll 			break;
45247e946e7SWyllys Ingersoll 	}
45347e946e7SWyllys Ingersoll 
45447e946e7SWyllys Ingersoll 	return (0);
45547e946e7SWyllys Ingersoll }
45647e946e7SWyllys Ingersoll 
45747e946e7SWyllys Ingersoll /* make sure the public exponent attribute is 65537 */
45847e946e7SWyllys Ingersoll static CK_ULONG
45947e946e7SWyllys Ingersoll util_check_public_exponent(TEMPLATE *tmpl)
46047e946e7SWyllys Ingersoll {
46147e946e7SWyllys Ingersoll 	CK_BBOOL flag;
46247e946e7SWyllys Ingersoll 	CK_ATTRIBUTE *publ_exp_attr;
46347e946e7SWyllys Ingersoll 	CK_BYTE pubexp_bytes[] = { 1, 0, 1 };
46447e946e7SWyllys Ingersoll 	CK_ULONG publ_exp, rc = 1;
46547e946e7SWyllys Ingersoll 
46647e946e7SWyllys Ingersoll 	flag = template_attribute_find(tmpl, CKA_PUBLIC_EXPONENT,
46747e946e7SWyllys Ingersoll 	    &publ_exp_attr);
46847e946e7SWyllys Ingersoll 	if (!flag) {
46947e946e7SWyllys Ingersoll 		LogError1("Couldn't find public exponent attribute");
47047e946e7SWyllys Ingersoll 		return (CKR_TEMPLATE_INCOMPLETE);
47147e946e7SWyllys Ingersoll 	}
47247e946e7SWyllys Ingersoll 
47347e946e7SWyllys Ingersoll 	switch (publ_exp_attr->ulValueLen) {
47447e946e7SWyllys Ingersoll 		case 3:
47547e946e7SWyllys Ingersoll 			rc = memcmp(pubexp_bytes, publ_exp_attr->pValue, 3);
47647e946e7SWyllys Ingersoll 			break;
47747e946e7SWyllys Ingersoll 		case sizeof (CK_ULONG):
47847e946e7SWyllys Ingersoll 			publ_exp = *((CK_ULONG *)publ_exp_attr->pValue);
47947e946e7SWyllys Ingersoll 			if (publ_exp == 65537)
48047e946e7SWyllys Ingersoll 				rc = 0;
48147e946e7SWyllys Ingersoll 			break;
48247e946e7SWyllys Ingersoll 		default:
48347e946e7SWyllys Ingersoll 			break;
48447e946e7SWyllys Ingersoll 	}
48547e946e7SWyllys Ingersoll 
48647e946e7SWyllys Ingersoll 	return (rc);
48747e946e7SWyllys Ingersoll }
48847e946e7SWyllys Ingersoll 
48947e946e7SWyllys Ingersoll TSS_RESULT
49047e946e7SWyllys Ingersoll set_public_modulus(TSS_HCONTEXT hContext, TSS_HKEY hKey,
49147e946e7SWyllys Ingersoll 	unsigned long size_n, unsigned char *n)
49247e946e7SWyllys Ingersoll {
49347e946e7SWyllys Ingersoll 	UINT64 offset;
49447e946e7SWyllys Ingersoll 	UINT32 blob_size;
49547e946e7SWyllys Ingersoll 	BYTE *blob, pub_blob[1024];
49647e946e7SWyllys Ingersoll 	TCPA_PUBKEY pub_key;
49747e946e7SWyllys Ingersoll 	TSS_RESULT result;
49847e946e7SWyllys Ingersoll 
49947e946e7SWyllys Ingersoll 	/* Get the TCPA_PUBKEY blob from the key object. */
50047e946e7SWyllys Ingersoll 	result = Tspi_GetAttribData(hKey, TSS_TSPATTRIB_KEY_BLOB,
50147e946e7SWyllys Ingersoll 	    TSS_TSPATTRIB_KEYBLOB_PUBLIC_KEY, &blob_size, &blob);
50247e946e7SWyllys Ingersoll 	if (result != TSS_SUCCESS) {
50347e946e7SWyllys Ingersoll 		stlogit("Tspi_GetAttribData failed: rc=0x%0x - %s\n",
50447e946e7SWyllys Ingersoll 		    result, Trspi_Error_String(result));
50547e946e7SWyllys Ingersoll 		return (result);
50647e946e7SWyllys Ingersoll 	}
50747e946e7SWyllys Ingersoll 
50847e946e7SWyllys Ingersoll 	offset = 0;
50947e946e7SWyllys Ingersoll 	result = Trspi_UnloadBlob_PUBKEY(&offset, blob, &pub_key);
51047e946e7SWyllys Ingersoll 	if (result != TSS_SUCCESS) {
51147e946e7SWyllys Ingersoll 		stlogit("Trspi_UnloadBlob_PUBKEY failed: rc=0x%0x - %s\n",
51247e946e7SWyllys Ingersoll 		    result, Trspi_Error_String(result));
51347e946e7SWyllys Ingersoll 		return (result);
51447e946e7SWyllys Ingersoll 	}
51547e946e7SWyllys Ingersoll 
51647e946e7SWyllys Ingersoll 	Tspi_Context_FreeMemory(hContext, blob);
51747e946e7SWyllys Ingersoll 	/* Free the first dangling reference, putting 'n' in its place */
51847e946e7SWyllys Ingersoll 	free(pub_key.pubKey.key);
51947e946e7SWyllys Ingersoll 	pub_key.pubKey.keyLength = size_n;
52047e946e7SWyllys Ingersoll 	pub_key.pubKey.key = n;
52147e946e7SWyllys Ingersoll 
52247e946e7SWyllys Ingersoll 	offset = 0;
52347e946e7SWyllys Ingersoll 	Trspi_LoadBlob_PUBKEY(&offset, pub_blob, &pub_key);
52447e946e7SWyllys Ingersoll 
52547e946e7SWyllys Ingersoll 	/* Free the second dangling reference */
52647e946e7SWyllys Ingersoll 	free(pub_key.algorithmParms.parms);
52747e946e7SWyllys Ingersoll 
52847e946e7SWyllys Ingersoll 	/* set the public key data in the TSS object */
52947e946e7SWyllys Ingersoll 	result = Tspi_SetAttribData(hKey, TSS_TSPATTRIB_KEY_BLOB,
53047e946e7SWyllys Ingersoll 	    TSS_TSPATTRIB_KEYBLOB_PUBLIC_KEY, (UINT32)offset, pub_blob);
53147e946e7SWyllys Ingersoll 	if (result != TSS_SUCCESS) {
53247e946e7SWyllys Ingersoll 		stlogit("Tspi_SetAttribData failed: rc=0x%0x - %s\n",
53347e946e7SWyllys Ingersoll 		    result, Trspi_Error_String(result));
53447e946e7SWyllys Ingersoll 		return (result);
53547e946e7SWyllys Ingersoll 	}
53647e946e7SWyllys Ingersoll 
53747e946e7SWyllys Ingersoll 	return (result);
53847e946e7SWyllys Ingersoll }
53947e946e7SWyllys Ingersoll 
54047e946e7SWyllys Ingersoll /*
54147e946e7SWyllys Ingersoll  * Get details about the TPM to put into the token_info structure.
54247e946e7SWyllys Ingersoll  */
54347e946e7SWyllys Ingersoll CK_RV
54447e946e7SWyllys Ingersoll token_get_tpm_info(TSS_HCONTEXT hContext, TOKEN_DATA *td)
54547e946e7SWyllys Ingersoll {
54647e946e7SWyllys Ingersoll 	TSS_RESULT result;
54747e946e7SWyllys Ingersoll 	TPM_CAPABILITY_AREA capArea = TSS_TPMCAP_VERSION_VAL;
54847e946e7SWyllys Ingersoll 	UINT32 datalen;
54947e946e7SWyllys Ingersoll 	BYTE *data;
55047e946e7SWyllys Ingersoll 	TSS_HTPM hTPM;
55147e946e7SWyllys Ingersoll 
55247e946e7SWyllys Ingersoll 	if ((result = Tspi_Context_GetTpmObject(hContext, &hTPM))) {
55347e946e7SWyllys Ingersoll 		stlogit("Tspi_Context_GetTpmObject: 0x%0x - %s",
55447e946e7SWyllys Ingersoll 		    result, Trspi_Error_String(result));
55547e946e7SWyllys Ingersoll 		return (CKR_FUNCTION_FAILED);
55647e946e7SWyllys Ingersoll 	}
55747e946e7SWyllys Ingersoll 	if ((result = Tspi_TPM_GetCapability(hTPM,
55847e946e7SWyllys Ingersoll 	    capArea, 0, NULL, &datalen, &data)) != 0 || datalen == 0 ||
55947e946e7SWyllys Ingersoll 	    data == NULL) {
56047e946e7SWyllys Ingersoll 		stlogit("Tspi_Context_GetCapability: 0x%0x - %s",
56147e946e7SWyllys Ingersoll 		    result, Trspi_Error_String(result));
56247e946e7SWyllys Ingersoll 		return (CKR_FUNCTION_FAILED);
56347e946e7SWyllys Ingersoll 	}
56447e946e7SWyllys Ingersoll 	if (datalen > sizeof (tpmvinfo)) {
56547e946e7SWyllys Ingersoll 		Tspi_Context_FreeMemory(hContext, data);
56647e946e7SWyllys Ingersoll 		return (CKR_FUNCTION_FAILED);
56747e946e7SWyllys Ingersoll 	}
56847e946e7SWyllys Ingersoll 
569*1dc1cb45SWyllys Ingersoll 	(void) memcpy(&tpmvinfo, (void *)data, datalen);
57047e946e7SWyllys Ingersoll 
57147e946e7SWyllys Ingersoll 	bzero(td->token_info.manufacturerID,
57247e946e7SWyllys Ingersoll 	    sizeof (td->token_info.manufacturerID));
57347e946e7SWyllys Ingersoll 
57447e946e7SWyllys Ingersoll 	(void) memset(td->token_info.manufacturerID,  ' ',
57547e946e7SWyllys Ingersoll 	    sizeof (td->token_info.manufacturerID) - 1);
576*1dc1cb45SWyllys Ingersoll 
57747e946e7SWyllys Ingersoll 	(void) memcpy(td->token_info.manufacturerID,
57847e946e7SWyllys Ingersoll 	    tpmvinfo.tpmVendorID, sizeof (tpmvinfo.tpmVendorID));
57947e946e7SWyllys Ingersoll 
58047e946e7SWyllys Ingersoll 	(void) memset(td->token_info.label, ' ',
58147e946e7SWyllys Ingersoll 	    sizeof (td->token_info.label) - 1);
582*1dc1cb45SWyllys Ingersoll 
583*1dc1cb45SWyllys Ingersoll 	(void) memcpy(td->token_info.label, "TPM", 3);
58447e946e7SWyllys Ingersoll 
58547e946e7SWyllys Ingersoll 	td->token_info.hardwareVersion.major = tpmvinfo.version.major;
58647e946e7SWyllys Ingersoll 	td->token_info.hardwareVersion.minor = tpmvinfo.version.minor;
58747e946e7SWyllys Ingersoll 	td->token_info.firmwareVersion.major = tpmvinfo.version.revMajor;
58847e946e7SWyllys Ingersoll 	td->token_info.firmwareVersion.minor = tpmvinfo.version.revMinor;
58947e946e7SWyllys Ingersoll 
59047e946e7SWyllys Ingersoll 	Tspi_Context_FreeMemory(hContext, data);
59147e946e7SWyllys Ingersoll 	return (CKR_OK);
59247e946e7SWyllys Ingersoll }
59347e946e7SWyllys Ingersoll 
59447e946e7SWyllys Ingersoll /*ARGSUSED*/
59547e946e7SWyllys Ingersoll CK_RV
59647e946e7SWyllys Ingersoll token_specific_session(CK_SLOT_ID  slotid)
59747e946e7SWyllys Ingersoll {
59847e946e7SWyllys Ingersoll 	return (CKR_OK);
59947e946e7SWyllys Ingersoll }
60047e946e7SWyllys Ingersoll 
60147e946e7SWyllys Ingersoll CK_RV
60247e946e7SWyllys Ingersoll token_rng(TSS_HCONTEXT hContext, CK_BYTE *output, CK_ULONG bytes)
60347e946e7SWyllys Ingersoll {
60447e946e7SWyllys Ingersoll 	TSS_RESULT rc;
60547e946e7SWyllys Ingersoll 	TSS_HTPM hTPM;
60647e946e7SWyllys Ingersoll 	BYTE *random_bytes = NULL;
60747e946e7SWyllys Ingersoll 
60847e946e7SWyllys Ingersoll 	if ((rc = Tspi_Context_GetTpmObject(hContext, &hTPM))) {
60947e946e7SWyllys Ingersoll 		stlogit("Tspi_Context_GetTpmObject: 0x%0x - %s",
61047e946e7SWyllys Ingersoll 		    rc, Trspi_Error_String(rc));
61147e946e7SWyllys Ingersoll 		return (CKR_FUNCTION_FAILED);
61247e946e7SWyllys Ingersoll 	}
61347e946e7SWyllys Ingersoll 
61447e946e7SWyllys Ingersoll 	if ((rc = Tspi_TPM_GetRandom(hTPM, bytes, &random_bytes))) {
61547e946e7SWyllys Ingersoll 		stlogit("Tspi_TPM_GetRandom: 0x%0x - %s",
61647e946e7SWyllys Ingersoll 		    rc, Trspi_Error_String(rc));
61747e946e7SWyllys Ingersoll 		return (CKR_FUNCTION_FAILED);
61847e946e7SWyllys Ingersoll 	}
61947e946e7SWyllys Ingersoll 
62047e946e7SWyllys Ingersoll 	(void) memcpy(output, random_bytes, bytes);
62147e946e7SWyllys Ingersoll 	Tspi_Context_FreeMemory(hContext, random_bytes);
62247e946e7SWyllys Ingersoll 
62347e946e7SWyllys Ingersoll 	return (CKR_OK);
62447e946e7SWyllys Ingersoll }
62547e946e7SWyllys Ingersoll 
62647e946e7SWyllys Ingersoll TSS_RESULT
62747e946e7SWyllys Ingersoll open_tss_context(TSS_HCONTEXT *pContext)
62847e946e7SWyllys Ingersoll {
62947e946e7SWyllys Ingersoll 	TSS_RESULT result;
63047e946e7SWyllys Ingersoll 
63147e946e7SWyllys Ingersoll 	if ((result = Tspi_Context_Create(pContext))) {
63247e946e7SWyllys Ingersoll 		stlogit("Tspi_Context_Create: 0x%0x - %s",
63347e946e7SWyllys Ingersoll 		    result, Trspi_Error_String(result));
63447e946e7SWyllys Ingersoll 		return (CKR_FUNCTION_FAILED);
63547e946e7SWyllys Ingersoll 	}
63647e946e7SWyllys Ingersoll 
63747e946e7SWyllys Ingersoll 	if ((result = Tspi_Context_Connect(*pContext, NULL))) {
63847e946e7SWyllys Ingersoll 		stlogit("Tspi_Context_Connect: 0x%0x - %s",
63947e946e7SWyllys Ingersoll 		    result, Trspi_Error_String(result));
64047e946e7SWyllys Ingersoll 		return (CKR_FUNCTION_FAILED);
64147e946e7SWyllys Ingersoll 	}
64247e946e7SWyllys Ingersoll 	return (result);
64347e946e7SWyllys Ingersoll }
64447e946e7SWyllys Ingersoll 
64547e946e7SWyllys Ingersoll /*ARGSUSED*/
64647e946e7SWyllys Ingersoll static CK_RV
64747e946e7SWyllys Ingersoll token_specific_init(char *Correlator, CK_SLOT_ID SlotNumber,
64847e946e7SWyllys Ingersoll     TSS_HCONTEXT *hContext)
64947e946e7SWyllys Ingersoll {
65047e946e7SWyllys Ingersoll 	TSS_RESULT result;
65147e946e7SWyllys Ingersoll 
65247e946e7SWyllys Ingersoll 	result = open_tss_context(hContext);
65347e946e7SWyllys Ingersoll 	if (result)
65447e946e7SWyllys Ingersoll 		return (CKR_FUNCTION_FAILED);
65547e946e7SWyllys Ingersoll 
65647e946e7SWyllys Ingersoll 	if ((result = Tspi_Context_GetDefaultPolicy(*hContext,
65747e946e7SWyllys Ingersoll 	    &hDefaultPolicy))) {
65847e946e7SWyllys Ingersoll 		stlogit("Tspi_Context_GetDefaultPolicy: 0x%0x - %s",
65947e946e7SWyllys Ingersoll 		    result, Trspi_Error_String(result));
66047e946e7SWyllys Ingersoll 		return (CKR_FUNCTION_FAILED);
66147e946e7SWyllys Ingersoll 	}
66247e946e7SWyllys Ingersoll 
66347e946e7SWyllys Ingersoll 	local_uuid_clear(&publicRootKeyUUID);
66447e946e7SWyllys Ingersoll 	local_uuid_clear(&privateRootKeyUUID);
66547e946e7SWyllys Ingersoll 	local_uuid_clear(&publicLeafKeyUUID);
66647e946e7SWyllys Ingersoll 	local_uuid_clear(&privateLeafKeyUUID);
66747e946e7SWyllys Ingersoll 
66847e946e7SWyllys Ingersoll 	result = token_get_tpm_info(*hContext, nv_token_data);
66947e946e7SWyllys Ingersoll 	return (result);
67047e946e7SWyllys Ingersoll }
67147e946e7SWyllys Ingersoll 
67247e946e7SWyllys Ingersoll /*
67347e946e7SWyllys Ingersoll  * Given a modulus and prime from an RSA key, create a TSS_HKEY object by
67447e946e7SWyllys Ingersoll  * wrapping the RSA key with a key from the TPM (SRK or other previously stored
67547e946e7SWyllys Ingersoll  * key).
67647e946e7SWyllys Ingersoll  */
67747e946e7SWyllys Ingersoll static CK_RV
67847e946e7SWyllys Ingersoll token_wrap_sw_key(
67947e946e7SWyllys Ingersoll 	TSS_HCONTEXT hContext,
68047e946e7SWyllys Ingersoll 	int size_n,
68147e946e7SWyllys Ingersoll 	unsigned char *n,
68247e946e7SWyllys Ingersoll 	int size_p,
68347e946e7SWyllys Ingersoll 	unsigned char *p,
68447e946e7SWyllys Ingersoll 	TSS_HKEY hParentKey,
68547e946e7SWyllys Ingersoll 	TSS_FLAG initFlags,
68647e946e7SWyllys Ingersoll 	TSS_HKEY *phKey)
68747e946e7SWyllys Ingersoll {
68847e946e7SWyllys Ingersoll 	TSS_RESULT result;
68947e946e7SWyllys Ingersoll 	UINT32 key_size;
69047e946e7SWyllys Ingersoll 
69147e946e7SWyllys Ingersoll 	key_size = util_get_keysize_flag(size_n * 8);
69247e946e7SWyllys Ingersoll 	if (initFlags == 0) {
69347e946e7SWyllys Ingersoll 		return (CKR_FUNCTION_FAILED);
69447e946e7SWyllys Ingersoll 	}
69547e946e7SWyllys Ingersoll 
69647e946e7SWyllys Ingersoll 	/* create the TSS key object */
69747e946e7SWyllys Ingersoll 	result = Tspi_Context_CreateObject(hContext, TSS_OBJECT_TYPE_RSAKEY,
69847e946e7SWyllys Ingersoll 	    TSS_KEY_MIGRATABLE | initFlags | key_size, phKey);
69947e946e7SWyllys Ingersoll 	if (result != TSS_SUCCESS) {
70047e946e7SWyllys Ingersoll 		stlogit("Tspi_Context_CreateObject: 0x%0x - %s",
70147e946e7SWyllys Ingersoll 		    result, Trspi_Error_String(result));
70247e946e7SWyllys Ingersoll 		return (CKR_FUNCTION_FAILED);
70347e946e7SWyllys Ingersoll 	}
70447e946e7SWyllys Ingersoll 
70547e946e7SWyllys Ingersoll 	result = set_public_modulus(hContext, *phKey, size_n, n);
70647e946e7SWyllys Ingersoll 	if (result != TSS_SUCCESS) {
70747e946e7SWyllys Ingersoll 		Tspi_Context_CloseObject(hContext, *phKey);
70847e946e7SWyllys Ingersoll 		*phKey = NULL_HKEY;
70947e946e7SWyllys Ingersoll 		return (CKR_FUNCTION_FAILED);
71047e946e7SWyllys Ingersoll 	}
71147e946e7SWyllys Ingersoll 
71247e946e7SWyllys Ingersoll 	/* set the private key data in the TSS object */
71347e946e7SWyllys Ingersoll 	result = Tspi_SetAttribData(*phKey, TSS_TSPATTRIB_KEY_BLOB,
71447e946e7SWyllys Ingersoll 	    TSS_TSPATTRIB_KEYBLOB_PRIVATE_KEY, size_p, p);
71547e946e7SWyllys Ingersoll 	if (result != TSS_SUCCESS) {
71647e946e7SWyllys Ingersoll 		stlogit("Tspi_SetAttribData: 0x%x - %s",
71747e946e7SWyllys Ingersoll 		    result, Trspi_Error_String(result));
71847e946e7SWyllys Ingersoll 		Tspi_Context_CloseObject(hContext, *phKey);
71947e946e7SWyllys Ingersoll 		*phKey = NULL_HKEY;
72047e946e7SWyllys Ingersoll 		return (CKR_FUNCTION_FAILED);
72147e946e7SWyllys Ingersoll 	}
72247e946e7SWyllys Ingersoll 
723ab8176c2SWyllys Ingersoll 	result = tss_assign_secret_key_policy(hContext, TSS_POLICY_MIGRATION,
724ab8176c2SWyllys Ingersoll 	    *phKey, NULL);
72547e946e7SWyllys Ingersoll 
72647e946e7SWyllys Ingersoll 	if (TPMTOK_TSS_KEY_TYPE(initFlags) == TSS_KEY_TYPE_LEGACY) {
72747e946e7SWyllys Ingersoll 		if ((result = Tspi_SetAttribUint32(*phKey,
72847e946e7SWyllys Ingersoll 		    TSS_TSPATTRIB_KEY_INFO, TSS_TSPATTRIB_KEYINFO_ENCSCHEME,
72947e946e7SWyllys Ingersoll 		    TSS_ES_RSAESPKCSV15))) {
73047e946e7SWyllys Ingersoll 			stlogit("Tspi_SetAttribUint32: 0x%0x - %s\n",
73147e946e7SWyllys Ingersoll 			    result, Trspi_Error_String(result));
73247e946e7SWyllys Ingersoll 			Tspi_Context_CloseObject(hContext, *phKey);
73347e946e7SWyllys Ingersoll 			return (CKR_FUNCTION_FAILED);
73447e946e7SWyllys Ingersoll 		}
73547e946e7SWyllys Ingersoll 
73647e946e7SWyllys Ingersoll 		if ((result = Tspi_SetAttribUint32(*phKey,
73747e946e7SWyllys Ingersoll 		    TSS_TSPATTRIB_KEY_INFO, TSS_TSPATTRIB_KEYINFO_SIGSCHEME,
73847e946e7SWyllys Ingersoll 		    TSS_SS_RSASSAPKCS1V15_DER))) {
73947e946e7SWyllys Ingersoll 			stlogit("Tspi_SetAttribUint32: 0x%0x - %s\n",
74047e946e7SWyllys Ingersoll 			    result, Trspi_Error_String(result));
74147e946e7SWyllys Ingersoll 			Tspi_Context_CloseObject(hContext, *phKey);
74247e946e7SWyllys Ingersoll 			return (CKR_FUNCTION_FAILED);
74347e946e7SWyllys Ingersoll 		}
74447e946e7SWyllys Ingersoll 	}
74547e946e7SWyllys Ingersoll 
74647e946e7SWyllys Ingersoll 	result = Tspi_Key_WrapKey(*phKey, hParentKey, NULL_HPCRS);
74747e946e7SWyllys Ingersoll 	if (result != TSS_SUCCESS) {
74847e946e7SWyllys Ingersoll 		stlogit("Tspi_Key_WrapKey: 0x%0x - %s",
74947e946e7SWyllys Ingersoll 		    result, Trspi_Error_String(result));
75047e946e7SWyllys Ingersoll 		Tspi_Context_CloseObject(hContext, *phKey);
75147e946e7SWyllys Ingersoll 		*phKey = NULL_HKEY;
75247e946e7SWyllys Ingersoll 		return (CKR_FUNCTION_FAILED);
75347e946e7SWyllys Ingersoll 	}
75447e946e7SWyllys Ingersoll 
75547e946e7SWyllys Ingersoll 	return (CKR_OK);
75647e946e7SWyllys Ingersoll }
75747e946e7SWyllys Ingersoll 
75847e946e7SWyllys Ingersoll /*
75947e946e7SWyllys Ingersoll  * Create a TPM key blob for an imported key. This function is only called when
76047e946e7SWyllys Ingersoll  * a key is in active use, so any failure should trickle through.
76147e946e7SWyllys Ingersoll  */
76247e946e7SWyllys Ingersoll static CK_RV
76347e946e7SWyllys Ingersoll token_wrap_key_object(TSS_HCONTEXT hContext,
76447e946e7SWyllys Ingersoll 	CK_OBJECT_HANDLE ckObject,
76547e946e7SWyllys Ingersoll 	TSS_HKEY hParentKey, TSS_HKEY *phKey)
76647e946e7SWyllys Ingersoll {
76747e946e7SWyllys Ingersoll 	CK_RV		rc = CKR_OK;
76847e946e7SWyllys Ingersoll 	CK_ATTRIBUTE	*attr = NULL, *new_attr, *prime_attr;
76947e946e7SWyllys Ingersoll 	CK_ULONG	class, key_type;
77047e946e7SWyllys Ingersoll 	OBJECT		*obj;
77147e946e7SWyllys Ingersoll 
77247e946e7SWyllys Ingersoll 	TSS_RESULT	result;
77347e946e7SWyllys Ingersoll 	TSS_FLAG	initFlags = 0;
77447e946e7SWyllys Ingersoll 	BYTE		*rgbBlob;
77547e946e7SWyllys Ingersoll 	UINT32		ulBlobLen;
77647e946e7SWyllys Ingersoll 
77747e946e7SWyllys Ingersoll 	if ((rc = object_mgr_find_in_map1(hContext, ckObject, &obj))) {
77847e946e7SWyllys Ingersoll 		return (rc);
77947e946e7SWyllys Ingersoll 	}
78047e946e7SWyllys Ingersoll 
78147e946e7SWyllys Ingersoll 	/* if the object isn't a key, fail */
78247e946e7SWyllys Ingersoll 	if (template_attribute_find(obj->template, CKA_KEY_TYPE,
78347e946e7SWyllys Ingersoll 	    &attr) == FALSE) {
78447e946e7SWyllys Ingersoll 		return (CKR_TEMPLATE_INCOMPLETE);
78547e946e7SWyllys Ingersoll 	}
78647e946e7SWyllys Ingersoll 
78747e946e7SWyllys Ingersoll 	key_type = *((CK_ULONG *)attr->pValue);
78847e946e7SWyllys Ingersoll 
78947e946e7SWyllys Ingersoll 	if (key_type != CKK_RSA) {
79047e946e7SWyllys Ingersoll 		return (CKR_TEMPLATE_INCONSISTENT);
79147e946e7SWyllys Ingersoll 	}
79247e946e7SWyllys Ingersoll 
79347e946e7SWyllys Ingersoll 	if (template_attribute_find(obj->template, CKA_CLASS,
79447e946e7SWyllys Ingersoll 	    &attr) == FALSE) {
79547e946e7SWyllys Ingersoll 		return (CKR_TEMPLATE_INCOMPLETE);
79647e946e7SWyllys Ingersoll 	}
79747e946e7SWyllys Ingersoll 
79847e946e7SWyllys Ingersoll 	class = *((CK_ULONG *)attr->pValue);
79947e946e7SWyllys Ingersoll 
80047e946e7SWyllys Ingersoll 	if (class == CKO_PRIVATE_KEY) {
80147e946e7SWyllys Ingersoll 		/*
80247e946e7SWyllys Ingersoll 		 * In order to create a full TSS key blob using a PKCS#11
80347e946e7SWyllys Ingersoll 		 * private key object, we need one of the two primes, the
80447e946e7SWyllys Ingersoll 		 * modulus and the private exponent and we need the public
80547e946e7SWyllys Ingersoll 		 * exponent to be correct.
80647e946e7SWyllys Ingersoll 		 */
80747e946e7SWyllys Ingersoll 
80847e946e7SWyllys Ingersoll 		/*
80947e946e7SWyllys Ingersoll 		 * Check the least likely attribute to exist first, the
81047e946e7SWyllys Ingersoll 		 * primes.
81147e946e7SWyllys Ingersoll 		 */
81247e946e7SWyllys Ingersoll 		if (template_attribute_find(obj->template, CKA_PRIME_1,
81347e946e7SWyllys Ingersoll 		    &prime_attr) == FALSE) {
81447e946e7SWyllys Ingersoll 			if (template_attribute_find(obj->template,
81547e946e7SWyllys Ingersoll 			    CKA_PRIME_2, &prime_attr) == FALSE) {
81647e946e7SWyllys Ingersoll 				return (CKR_TEMPLATE_INCOMPLETE);
81747e946e7SWyllys Ingersoll 			}
81847e946e7SWyllys Ingersoll 		}
81947e946e7SWyllys Ingersoll 
82047e946e7SWyllys Ingersoll 		/* Make sure the public exponent is usable */
82147e946e7SWyllys Ingersoll 		if ((rc = util_check_public_exponent(obj->template))) {
82247e946e7SWyllys Ingersoll 			return (CKR_TEMPLATE_INCONSISTENT);
82347e946e7SWyllys Ingersoll 		}
82447e946e7SWyllys Ingersoll 
82547e946e7SWyllys Ingersoll 		/* get the modulus */
82647e946e7SWyllys Ingersoll 		if (template_attribute_find(obj->template, CKA_MODULUS,
82747e946e7SWyllys Ingersoll 		    &attr) == FALSE) {
82847e946e7SWyllys Ingersoll 			return (CKR_TEMPLATE_INCOMPLETE);
82947e946e7SWyllys Ingersoll 		}
83047e946e7SWyllys Ingersoll 
83147e946e7SWyllys Ingersoll 		/* make sure the key size is usable */
83247e946e7SWyllys Ingersoll 		initFlags = util_get_keysize_flag(attr->ulValueLen * 8);
83347e946e7SWyllys Ingersoll 		if (initFlags == 0) {
83447e946e7SWyllys Ingersoll 			return (CKR_TEMPLATE_INCONSISTENT);
83547e946e7SWyllys Ingersoll 		}
83647e946e7SWyllys Ingersoll 
83747e946e7SWyllys Ingersoll 		/* generate the software based key */
83847e946e7SWyllys Ingersoll 		if ((rc = token_wrap_sw_key(hContext,
83947e946e7SWyllys Ingersoll 		    (int)attr->ulValueLen, attr->pValue,
84047e946e7SWyllys Ingersoll 		    (int)prime_attr->ulValueLen, prime_attr->pValue,
84147e946e7SWyllys Ingersoll 		    hParentKey, TSS_KEY_TYPE_LEGACY | TSS_KEY_NO_AUTHORIZATION,
84247e946e7SWyllys Ingersoll 		    phKey))) {
84347e946e7SWyllys Ingersoll 			return (rc);
84447e946e7SWyllys Ingersoll 		}
84547e946e7SWyllys Ingersoll 	} else if (class == CKO_PUBLIC_KEY) {
84647e946e7SWyllys Ingersoll 		/* Make sure the public exponent is usable */
84747e946e7SWyllys Ingersoll 		if ((util_check_public_exponent(obj->template))) {
84847e946e7SWyllys Ingersoll 			return (CKR_TEMPLATE_INCONSISTENT);
84947e946e7SWyllys Ingersoll 		}
85047e946e7SWyllys Ingersoll 
85147e946e7SWyllys Ingersoll 		/* grab the modulus to put into the TSS key object */
85247e946e7SWyllys Ingersoll 		if (template_attribute_find(obj->template,
85347e946e7SWyllys Ingersoll 		    CKA_MODULUS, &attr) == FALSE) {
85447e946e7SWyllys Ingersoll 			return (CKR_TEMPLATE_INCONSISTENT);
85547e946e7SWyllys Ingersoll 		}
85647e946e7SWyllys Ingersoll 
85747e946e7SWyllys Ingersoll 		/* make sure the key size is usable */
85847e946e7SWyllys Ingersoll 		initFlags = util_get_keysize_flag(attr->ulValueLen * 8);
85947e946e7SWyllys Ingersoll 		if (initFlags == 0) {
86047e946e7SWyllys Ingersoll 			return (CKR_TEMPLATE_INCONSISTENT);
86147e946e7SWyllys Ingersoll 		}
86247e946e7SWyllys Ingersoll 
863ab8176c2SWyllys Ingersoll 		initFlags |= TSS_KEY_MIGRATABLE | TSS_KEY_NO_AUTHORIZATION |
864ab8176c2SWyllys Ingersoll 		    TSS_KEY_TYPE_LEGACY;
86547e946e7SWyllys Ingersoll 
86647e946e7SWyllys Ingersoll 		if ((result = Tspi_Context_CreateObject(hContext,
86747e946e7SWyllys Ingersoll 		    TSS_OBJECT_TYPE_RSAKEY, initFlags, phKey))) {
86847e946e7SWyllys Ingersoll 			stlogit("Tspi_Context_CreateObject: 0x%0x - %s",
86947e946e7SWyllys Ingersoll 			    result, Trspi_Error_String(result));
87047e946e7SWyllys Ingersoll 			return (result);
87147e946e7SWyllys Ingersoll 		}
87247e946e7SWyllys Ingersoll 
87347e946e7SWyllys Ingersoll 		if ((result = set_public_modulus(hContext, *phKey,
87447e946e7SWyllys Ingersoll 		    attr->ulValueLen, attr->pValue))) {
87547e946e7SWyllys Ingersoll 			Tspi_Context_CloseObject(hContext, *phKey);
87647e946e7SWyllys Ingersoll 			*phKey = NULL_HKEY;
87747e946e7SWyllys Ingersoll 			return (CKR_FUNCTION_FAILED);
87847e946e7SWyllys Ingersoll 		}
879ab8176c2SWyllys Ingersoll 		result = tss_assign_secret_key_policy(hContext,
880ab8176c2SWyllys Ingersoll 		    TSS_POLICY_MIGRATION, *phKey, NULL);
881ab8176c2SWyllys Ingersoll 		if (result) {
882ab8176c2SWyllys Ingersoll 			Tspi_Context_CloseObject(hContext, *phKey);
883ab8176c2SWyllys Ingersoll 			*phKey = NULL_HKEY;
884ab8176c2SWyllys Ingersoll 			return (CKR_FUNCTION_FAILED);
885ab8176c2SWyllys Ingersoll 		}
886ab8176c2SWyllys Ingersoll 
887ab8176c2SWyllys Ingersoll 		result = set_legacy_key_params(*phKey);
888ab8176c2SWyllys Ingersoll 		if (result) {
889ab8176c2SWyllys Ingersoll 			Tspi_Context_CloseObject(hContext, *phKey);
890ab8176c2SWyllys Ingersoll 			*phKey = NULL_HKEY;
891ab8176c2SWyllys Ingersoll 			return (CKR_FUNCTION_FAILED);
892ab8176c2SWyllys Ingersoll 		}
89347e946e7SWyllys Ingersoll 	} else {
89447e946e7SWyllys Ingersoll 		return (CKR_FUNCTION_FAILED);
89547e946e7SWyllys Ingersoll 	}
89647e946e7SWyllys Ingersoll 
89747e946e7SWyllys Ingersoll 	/* grab the entire key blob to put into the PKCS#11 object */
89847e946e7SWyllys Ingersoll 	if ((result = Tspi_GetAttribData(*phKey, TSS_TSPATTRIB_KEY_BLOB,
89947e946e7SWyllys Ingersoll 	    TSS_TSPATTRIB_KEYBLOB_BLOB, &ulBlobLen, &rgbBlob))) {
90047e946e7SWyllys Ingersoll 		stlogit("Tspi_GetAttribData: 0x%0x - %s",
90147e946e7SWyllys Ingersoll 		    result, Trspi_Error_String(result));
90247e946e7SWyllys Ingersoll 		return (CKR_FUNCTION_FAILED);
90347e946e7SWyllys Ingersoll 	}
90447e946e7SWyllys Ingersoll 
90547e946e7SWyllys Ingersoll 	/* insert the key blob into the object */
90647e946e7SWyllys Ingersoll 	if ((rc = build_attribute(CKA_IBM_OPAQUE, rgbBlob, ulBlobLen,
90747e946e7SWyllys Ingersoll 	    &new_attr))) {
90847e946e7SWyllys Ingersoll 		Tspi_Context_FreeMemory(hContext, rgbBlob);
90947e946e7SWyllys Ingersoll 		return (rc);
91047e946e7SWyllys Ingersoll 	}
91147e946e7SWyllys Ingersoll 	(void) template_update_attribute(obj->template, new_attr);
91247e946e7SWyllys Ingersoll 	Tspi_Context_FreeMemory(hContext, rgbBlob);
91347e946e7SWyllys Ingersoll 
91447e946e7SWyllys Ingersoll 	/*
91547e946e7SWyllys Ingersoll 	 * If this is a token object, save it with the new attribute
91647e946e7SWyllys Ingersoll 	 * so that we don't have to go down this path again.
91747e946e7SWyllys Ingersoll 	 */
91847e946e7SWyllys Ingersoll 	if (!object_is_session_object(obj)) {
91947e946e7SWyllys Ingersoll 		rc = save_token_object(hContext, obj);
92047e946e7SWyllys Ingersoll 	}
92147e946e7SWyllys Ingersoll 
92247e946e7SWyllys Ingersoll 	return (rc);
92347e946e7SWyllys Ingersoll }
92447e946e7SWyllys Ingersoll 
92547e946e7SWyllys Ingersoll static TSS_RESULT
926ab8176c2SWyllys Ingersoll tss_assign_secret_key_policy(TSS_HCONTEXT hContext, TSS_FLAG policyType,
927ab8176c2SWyllys Ingersoll     TSS_HKEY hKey, CK_CHAR *passHash)
92847e946e7SWyllys Ingersoll {
92947e946e7SWyllys Ingersoll 	TSS_RESULT result;
93047e946e7SWyllys Ingersoll 	TSS_HPOLICY hPolicy;
93147e946e7SWyllys Ingersoll 
93247e946e7SWyllys Ingersoll 	if ((result = Tspi_Context_CreateObject(hContext,
933ab8176c2SWyllys Ingersoll 	    TSS_OBJECT_TYPE_POLICY, policyType, &hPolicy))) {
93447e946e7SWyllys Ingersoll 		stlogit("Tspi_Context_CreateObject: 0x%0x - %s",
93547e946e7SWyllys Ingersoll 		    result, Trspi_Error_String(result));
93647e946e7SWyllys Ingersoll 		return (result);
93747e946e7SWyllys Ingersoll 	}
93847e946e7SWyllys Ingersoll 	if ((result = Tspi_Policy_AssignToObject(hPolicy, hKey))) {
93947e946e7SWyllys Ingersoll 		stlogit("Tspi_Policy_AssignToObject: 0x%0x - %s",
94047e946e7SWyllys Ingersoll 		    result, Trspi_Error_String(result));
94147e946e7SWyllys Ingersoll 		goto done;
94247e946e7SWyllys Ingersoll 	}
94347e946e7SWyllys Ingersoll 	if (passHash == NULL) {
94447e946e7SWyllys Ingersoll 		result = Tspi_Policy_SetSecret(hPolicy, TSS_SECRET_MODE_NONE,
94547e946e7SWyllys Ingersoll 		    0, NULL);
94647e946e7SWyllys Ingersoll 	} else {
94747e946e7SWyllys Ingersoll 		result = Tspi_Policy_SetSecret(hPolicy, TSS_SECRET_MODE_SHA1,
94847e946e7SWyllys Ingersoll 		    SHA1_DIGEST_LENGTH, passHash);
94947e946e7SWyllys Ingersoll 	}
95047e946e7SWyllys Ingersoll 	if (result != TSS_SUCCESS) {
95147e946e7SWyllys Ingersoll 		stlogit("Tspi_Policy_SetSecret: 0x%0x - %s",
95247e946e7SWyllys Ingersoll 		    result, Trspi_Error_String(result));
95347e946e7SWyllys Ingersoll 		goto done;
95447e946e7SWyllys Ingersoll 	}
95547e946e7SWyllys Ingersoll done:
95647e946e7SWyllys Ingersoll 	if (result != TSS_SUCCESS)
95747e946e7SWyllys Ingersoll 		Tspi_Context_CloseObject(hContext, hPolicy);
95847e946e7SWyllys Ingersoll 	return (result);
95947e946e7SWyllys Ingersoll }
96047e946e7SWyllys Ingersoll 
96147e946e7SWyllys Ingersoll /*
96247e946e7SWyllys Ingersoll  * Take a key from the TSS store (on-disk) and load it into the TPM, wrapped
96347e946e7SWyllys Ingersoll  * by an already TPM-resident key and protected with a PIN (optional).
96447e946e7SWyllys Ingersoll  */
96547e946e7SWyllys Ingersoll static CK_RV
96647e946e7SWyllys Ingersoll token_load_key(
96747e946e7SWyllys Ingersoll 	TSS_HCONTEXT hContext,
96847e946e7SWyllys Ingersoll 	CK_OBJECT_HANDLE ckKey,
96947e946e7SWyllys Ingersoll 	TSS_HKEY hParentKey,
97047e946e7SWyllys Ingersoll 	CK_CHAR_PTR passHash,
97147e946e7SWyllys Ingersoll 	TSS_HKEY *phKey)
97247e946e7SWyllys Ingersoll {
97347e946e7SWyllys Ingersoll 	TSS_RESULT result;
97447e946e7SWyllys Ingersoll 	CK_RV rc;
97547e946e7SWyllys Ingersoll 
97647e946e7SWyllys Ingersoll 	/*
97747e946e7SWyllys Ingersoll 	 * The key blob wasn't found, load the parts of the key
97847e946e7SWyllys Ingersoll 	 * from the object DB and create a new key object that
97947e946e7SWyllys Ingersoll 	 * gets loaded into the TPM, wrapped with the parent key.
98047e946e7SWyllys Ingersoll 	 */
98147e946e7SWyllys Ingersoll 	if ((rc = token_wrap_key_object(hContext, ckKey,
98247e946e7SWyllys Ingersoll 	    hParentKey, phKey))) {
98347e946e7SWyllys Ingersoll 		return (rc);
98447e946e7SWyllys Ingersoll 	}
98547e946e7SWyllys Ingersoll 
98647e946e7SWyllys Ingersoll 	/*
98747e946e7SWyllys Ingersoll 	 * Assign the PIN hash (optional) to the newly loaded key object,
98847e946e7SWyllys Ingersoll 	 * if this PIN is incorrect, the TPM will not be able to decrypt
98947e946e7SWyllys Ingersoll 	 * the private key and use it.
99047e946e7SWyllys Ingersoll 	 */
991ab8176c2SWyllys Ingersoll 	result = tss_assign_secret_key_policy(hContext, TSS_POLICY_USAGE,
992ab8176c2SWyllys Ingersoll 	    *phKey, passHash);
993ab8176c2SWyllys Ingersoll 
99447e946e7SWyllys Ingersoll 	return (result);
99547e946e7SWyllys Ingersoll }
99647e946e7SWyllys Ingersoll 
99747e946e7SWyllys Ingersoll /*
99847e946e7SWyllys Ingersoll  * Load the SRK into the TPM by referencing its well-known UUID and using the
99947e946e7SWyllys Ingersoll  * default SRK PIN (20 bytes of 0x00).
100047e946e7SWyllys Ingersoll  *
100147e946e7SWyllys Ingersoll  * NOTE - if the SRK PIN is changed by an administrative tool, this code will
100247e946e7SWyllys Ingersoll  * fail because it assumes that the well-known PIN is still being used.
100347e946e7SWyllys Ingersoll  */
100447e946e7SWyllys Ingersoll static TSS_RESULT
100547e946e7SWyllys Ingersoll token_load_srk(TSS_HCONTEXT hContext, TSS_HKEY *hSRK)
100647e946e7SWyllys Ingersoll {
100747e946e7SWyllys Ingersoll 	TSS_HPOLICY hPolicy;
100847e946e7SWyllys Ingersoll 	TSS_RESULT result;
100947e946e7SWyllys Ingersoll 	TSS_UUID SRK_UUID = TSS_UUID_SRK;
101047e946e7SWyllys Ingersoll 	BYTE wellKnown[] = TSS_WELL_KNOWN_SECRET;
101147e946e7SWyllys Ingersoll 	TSS_HTPM hTPM;
101247e946e7SWyllys Ingersoll 
101347e946e7SWyllys Ingersoll 	if ((result = Tspi_Context_GetTpmObject(hContext, &hTPM))) {
101447e946e7SWyllys Ingersoll 		stlogit("Tspi_Context_GetTpmObject: 0x%0x - %s",
101547e946e7SWyllys Ingersoll 		    result, Trspi_Error_String(result));
101647e946e7SWyllys Ingersoll 		return (CKR_FUNCTION_FAILED);
101747e946e7SWyllys Ingersoll 	}
101847e946e7SWyllys Ingersoll 
101947e946e7SWyllys Ingersoll 	/* load the SRK */
102047e946e7SWyllys Ingersoll 	if ((result = Tspi_Context_LoadKeyByUUID(hContext,
102147e946e7SWyllys Ingersoll 	    TSS_PS_TYPE_SYSTEM, SRK_UUID, hSRK))) {
102247e946e7SWyllys Ingersoll 		stlogit("Tspi_Context_LoadKeyByUUID: 0x%0x - %s",
102347e946e7SWyllys Ingersoll 		    result, Trspi_Error_String(result));
102447e946e7SWyllys Ingersoll 		goto done;
102547e946e7SWyllys Ingersoll 	}
102647e946e7SWyllys Ingersoll 	if ((result = Tspi_GetPolicyObject(*hSRK, TSS_POLICY_USAGE,
102747e946e7SWyllys Ingersoll 	    &hPolicy))) {
102847e946e7SWyllys Ingersoll 		stlogit("Tspi_GetPolicyObject: 0x%0x - %s",
102947e946e7SWyllys Ingersoll 		    result, Trspi_Error_String(result));
103047e946e7SWyllys Ingersoll 		goto done;
103147e946e7SWyllys Ingersoll 	}
103247e946e7SWyllys Ingersoll 	if ((result = Tspi_Policy_SetSecret(hPolicy, TSS_SECRET_MODE_SHA1,
103347e946e7SWyllys Ingersoll 	    sizeof (wellKnown), wellKnown))) {
103447e946e7SWyllys Ingersoll 		stlogit("Tspi_Policy_SetSecret: 0x%0x - %s",
103547e946e7SWyllys Ingersoll 		    result, Trspi_Error_String(result));
103647e946e7SWyllys Ingersoll 		goto done;
103747e946e7SWyllys Ingersoll 	}
103847e946e7SWyllys Ingersoll 
103947e946e7SWyllys Ingersoll done:
104047e946e7SWyllys Ingersoll 	return (result);
104147e946e7SWyllys Ingersoll }
104247e946e7SWyllys Ingersoll 
104347e946e7SWyllys Ingersoll static TSS_RESULT
104447e946e7SWyllys Ingersoll tss_find_and_load_key(TSS_HCONTEXT hContext,
104547e946e7SWyllys Ingersoll 	char *keyid, TSS_UUID *uuid, TSS_HKEY hParent,
104647e946e7SWyllys Ingersoll 	BYTE *hash, TSS_HKEY *hKey)
104747e946e7SWyllys Ingersoll {
104847e946e7SWyllys Ingersoll 	TSS_RESULT result;
104947e946e7SWyllys Ingersoll 
105047e946e7SWyllys Ingersoll 	if (local_uuid_is_null(uuid) &&
105147e946e7SWyllys Ingersoll 	    find_uuid(keyid, uuid)) {
105247e946e7SWyllys Ingersoll 		/* The UUID was not created or saved yet */
105347e946e7SWyllys Ingersoll 		return (1);
105447e946e7SWyllys Ingersoll 	}
105547e946e7SWyllys Ingersoll 	result = Tspi_Context_GetKeyByUUID(hContext,
105647e946e7SWyllys Ingersoll 	    TSS_PS_TYPE_USER, *uuid, hKey);
105747e946e7SWyllys Ingersoll 	if (result) {
105847e946e7SWyllys Ingersoll 		stlogit("Tspi_Context_GetKeyByUUID: 0x%0x - %s",
105947e946e7SWyllys Ingersoll 		    result, Trspi_Error_String(result));
106047e946e7SWyllys Ingersoll 		return (result);
106147e946e7SWyllys Ingersoll 	}
106247e946e7SWyllys Ingersoll 
106347e946e7SWyllys Ingersoll 	if (hash != NULL) {
1064ab8176c2SWyllys Ingersoll 		result = tss_assign_secret_key_policy(hContext,
1065ab8176c2SWyllys Ingersoll 		    TSS_POLICY_USAGE, *hKey, (CK_BYTE *)hash);
106647e946e7SWyllys Ingersoll 		if (result)
106747e946e7SWyllys Ingersoll 			return (result);
106847e946e7SWyllys Ingersoll 	}
106947e946e7SWyllys Ingersoll 
107047e946e7SWyllys Ingersoll 	result = Tspi_Key_LoadKey(*hKey, hParent);
107147e946e7SWyllys Ingersoll 	if (result)
107247e946e7SWyllys Ingersoll 		stlogit("Tspi_Key_LoadKey: 0x%0x - %s",
107347e946e7SWyllys Ingersoll 		    result, Trspi_Error_String(result));
107447e946e7SWyllys Ingersoll 
107547e946e7SWyllys Ingersoll 	return (result);
107647e946e7SWyllys Ingersoll }
107747e946e7SWyllys Ingersoll 
107847e946e7SWyllys Ingersoll static TSS_RESULT
107947e946e7SWyllys Ingersoll token_load_public_root_key(TSS_HCONTEXT hContext)
108047e946e7SWyllys Ingersoll {
108147e946e7SWyllys Ingersoll 	TSS_RESULT result;
108247e946e7SWyllys Ingersoll 	TSS_HKEY hSRK;
108347e946e7SWyllys Ingersoll 
108447e946e7SWyllys Ingersoll 	if (hPublicRootKey != NULL_HKEY)
108547e946e7SWyllys Ingersoll 		return (TSS_SUCCESS);
108647e946e7SWyllys Ingersoll 
108747e946e7SWyllys Ingersoll 	if ((result = token_load_srk(hContext, &hSRK))) {
108847e946e7SWyllys Ingersoll 		return (result);
108947e946e7SWyllys Ingersoll 	}
109047e946e7SWyllys Ingersoll 
109147e946e7SWyllys Ingersoll 	result = tss_find_and_load_key(hContext,
109247e946e7SWyllys Ingersoll 	    TPMTOK_PUBLIC_ROOT_KEY_ID,
109347e946e7SWyllys Ingersoll 	    &publicRootKeyUUID, hSRK, NULL, &hPublicRootKey);
109447e946e7SWyllys Ingersoll 	if (result)
109547e946e7SWyllys Ingersoll 		return (result);
109647e946e7SWyllys Ingersoll 
109747e946e7SWyllys Ingersoll 	return (result);
109847e946e7SWyllys Ingersoll }
109947e946e7SWyllys Ingersoll 
110047e946e7SWyllys Ingersoll static TSS_RESULT
1101ab8176c2SWyllys Ingersoll set_legacy_key_params(TSS_HKEY hKey)
1102ab8176c2SWyllys Ingersoll {
1103ab8176c2SWyllys Ingersoll 	TSS_RESULT result;
1104ab8176c2SWyllys Ingersoll 
1105ab8176c2SWyllys Ingersoll 	if ((result = Tspi_SetAttribUint32(hKey,
1106ab8176c2SWyllys Ingersoll 	    TSS_TSPATTRIB_KEY_INFO,
1107ab8176c2SWyllys Ingersoll 	    TSS_TSPATTRIB_KEYINFO_ENCSCHEME,
1108ab8176c2SWyllys Ingersoll 	    TSS_ES_RSAESPKCSV15))) {
1109ab8176c2SWyllys Ingersoll 		stlogit("Tspi_SetAttribUint32: 0x%0x - %s",
1110ab8176c2SWyllys Ingersoll 		    result, Trspi_Error_String(result));
1111ab8176c2SWyllys Ingersoll 		return (result);
1112ab8176c2SWyllys Ingersoll 	}
1113ab8176c2SWyllys Ingersoll 
1114ab8176c2SWyllys Ingersoll 	if ((result = Tspi_SetAttribUint32(hKey,
1115ab8176c2SWyllys Ingersoll 	    TSS_TSPATTRIB_KEY_INFO,
1116ab8176c2SWyllys Ingersoll 	    TSS_TSPATTRIB_KEYINFO_SIGSCHEME,
1117ab8176c2SWyllys Ingersoll 	    TSS_SS_RSASSAPKCS1V15_DER))) {
1118ab8176c2SWyllys Ingersoll 		stlogit("Tspi_SetAttribUint32: 0x%0x - %s",
1119ab8176c2SWyllys Ingersoll 		    result, Trspi_Error_String(result));
1120ab8176c2SWyllys Ingersoll 		return (result);
1121ab8176c2SWyllys Ingersoll 	}
1122ab8176c2SWyllys Ingersoll 
1123ab8176c2SWyllys Ingersoll 	return (result);
1124ab8176c2SWyllys Ingersoll }
1125ab8176c2SWyllys Ingersoll 
1126ab8176c2SWyllys Ingersoll static TSS_RESULT
112747e946e7SWyllys Ingersoll tss_generate_key(TSS_HCONTEXT hContext, TSS_FLAG initFlags, BYTE *passHash,
112847e946e7SWyllys Ingersoll 	TSS_HKEY hParentKey, TSS_HKEY *phKey)
112947e946e7SWyllys Ingersoll {
113047e946e7SWyllys Ingersoll 	TSS_RESULT	result;
113147e946e7SWyllys Ingersoll 	TSS_HPOLICY	hMigPolicy;
113247e946e7SWyllys Ingersoll 
113347e946e7SWyllys Ingersoll 	if ((result = Tspi_Context_CreateObject(hContext,
113447e946e7SWyllys Ingersoll 	    TSS_OBJECT_TYPE_RSAKEY, initFlags, phKey))) {
113547e946e7SWyllys Ingersoll 		stlogit("Tspi_Context_CreateObject: 0x%0x - %s",
113647e946e7SWyllys Ingersoll 		    result, Trspi_Error_String(result));
113747e946e7SWyllys Ingersoll 		return (result);
113847e946e7SWyllys Ingersoll 	}
1139ab8176c2SWyllys Ingersoll 	result = tss_assign_secret_key_policy(hContext, TSS_POLICY_USAGE,
1140ab8176c2SWyllys Ingersoll 	    *phKey, passHash);
114147e946e7SWyllys Ingersoll 
114247e946e7SWyllys Ingersoll 	if (result) {
114347e946e7SWyllys Ingersoll 		Tspi_Context_CloseObject(hContext, *phKey);
114447e946e7SWyllys Ingersoll 		return (result);
114547e946e7SWyllys Ingersoll 	}
114647e946e7SWyllys Ingersoll 
114747e946e7SWyllys Ingersoll 	if (TPMTOK_TSS_KEY_MIG_TYPE(initFlags) == TSS_KEY_MIGRATABLE) {
114847e946e7SWyllys Ingersoll 		if ((result = Tspi_Context_CreateObject(hContext,
114947e946e7SWyllys Ingersoll 		    TSS_OBJECT_TYPE_POLICY, TSS_POLICY_MIGRATION,
115047e946e7SWyllys Ingersoll 		    &hMigPolicy))) {
115147e946e7SWyllys Ingersoll 			stlogit("Tspi_Context_CreateObject: 0x%0x - %s",
115247e946e7SWyllys Ingersoll 			    result, Trspi_Error_String(result));
115347e946e7SWyllys Ingersoll 			Tspi_Context_CloseObject(hContext, *phKey);
115447e946e7SWyllys Ingersoll 			return (result);
115547e946e7SWyllys Ingersoll 		}
115647e946e7SWyllys Ingersoll 
115747e946e7SWyllys Ingersoll 		if (passHash == NULL) {
115847e946e7SWyllys Ingersoll 			result = Tspi_Policy_SetSecret(hMigPolicy,
115947e946e7SWyllys Ingersoll 			    TSS_SECRET_MODE_NONE, 0, NULL);
116047e946e7SWyllys Ingersoll 		} else {
116147e946e7SWyllys Ingersoll 			result = Tspi_Policy_SetSecret(hMigPolicy,
116247e946e7SWyllys Ingersoll 			    TSS_SECRET_MODE_SHA1, 20, passHash);
116347e946e7SWyllys Ingersoll 		}
116447e946e7SWyllys Ingersoll 
116547e946e7SWyllys Ingersoll 		if (result != TSS_SUCCESS) {
116647e946e7SWyllys Ingersoll 			stlogit("Tspi_Policy_SetSecret: 0x%0x - %s",
116747e946e7SWyllys Ingersoll 			    result, Trspi_Error_String(result));
116847e946e7SWyllys Ingersoll 			Tspi_Context_CloseObject(hContext, *phKey);
116947e946e7SWyllys Ingersoll 			Tspi_Context_CloseObject(hContext, hMigPolicy);
117047e946e7SWyllys Ingersoll 			return (result);
117147e946e7SWyllys Ingersoll 		}
117247e946e7SWyllys Ingersoll 
117347e946e7SWyllys Ingersoll 		if ((result = Tspi_Policy_AssignToObject(hMigPolicy, *phKey))) {
117447e946e7SWyllys Ingersoll 			stlogit("Tspi_Policy_AssignToObject: 0x%0x - %s",
117547e946e7SWyllys Ingersoll 			    result, Trspi_Error_String(result));
117647e946e7SWyllys Ingersoll 			Tspi_Context_CloseObject(hContext, *phKey);
117747e946e7SWyllys Ingersoll 			Tspi_Context_CloseObject(hContext, hMigPolicy);
117847e946e7SWyllys Ingersoll 			return (result);
117947e946e7SWyllys Ingersoll 		}
118047e946e7SWyllys Ingersoll 	}
118147e946e7SWyllys Ingersoll 
118247e946e7SWyllys Ingersoll 	if (TPMTOK_TSS_KEY_TYPE(initFlags) == TSS_KEY_TYPE_LEGACY) {
1183ab8176c2SWyllys Ingersoll 		result = set_legacy_key_params(*phKey);
1184ab8176c2SWyllys Ingersoll 		if (result) {
118547e946e7SWyllys Ingersoll 			Tspi_Context_CloseObject(hContext, *phKey);
118647e946e7SWyllys Ingersoll 			Tspi_Context_CloseObject(hContext, hMigPolicy);
118747e946e7SWyllys Ingersoll 			return (result);
118847e946e7SWyllys Ingersoll 		}
118947e946e7SWyllys Ingersoll 	}
119047e946e7SWyllys Ingersoll 
119147e946e7SWyllys Ingersoll 	if ((result = Tspi_Key_CreateKey(*phKey, hParentKey, 0))) {
119247e946e7SWyllys Ingersoll 		stlogit("Tspi_Key_CreateKey: 0x%0x - %s",
119347e946e7SWyllys Ingersoll 		    result, Trspi_Error_String(result));
119447e946e7SWyllys Ingersoll 		Tspi_Context_CloseObject(hContext, *phKey);
119547e946e7SWyllys Ingersoll 		Tspi_Context_CloseObject(hContext, hMigPolicy);
119647e946e7SWyllys Ingersoll 	}
119747e946e7SWyllys Ingersoll 
119847e946e7SWyllys Ingersoll 	return (result);
119947e946e7SWyllys Ingersoll }
120047e946e7SWyllys Ingersoll 
120147e946e7SWyllys Ingersoll static TSS_RESULT
120247e946e7SWyllys Ingersoll tss_change_auth(
120347e946e7SWyllys Ingersoll 	TSS_HCONTEXT hContext,
120447e946e7SWyllys Ingersoll 	TSS_HKEY hObjectToChange, TSS_HKEY hParentObject,
120547e946e7SWyllys Ingersoll 	TSS_UUID objUUID, TSS_UUID parentUUID,
120647e946e7SWyllys Ingersoll 	CK_CHAR *passHash)
120747e946e7SWyllys Ingersoll {
120847e946e7SWyllys Ingersoll 	TSS_RESULT result;
120947e946e7SWyllys Ingersoll 	TSS_HPOLICY hPolicy;
121047e946e7SWyllys Ingersoll 	TSS_HKEY oldkey;
121147e946e7SWyllys Ingersoll 
121247e946e7SWyllys Ingersoll 	if ((result = Tspi_Context_CreateObject(hContext,
121347e946e7SWyllys Ingersoll 	    TSS_OBJECT_TYPE_POLICY, TSS_POLICY_USAGE, &hPolicy))) {
121447e946e7SWyllys Ingersoll 		stlogit("Tspi_Context_CreateObject: 0x%0x - %s",
121547e946e7SWyllys Ingersoll 		    result, Trspi_Error_String(result));
121647e946e7SWyllys Ingersoll 		return (result);
121747e946e7SWyllys Ingersoll 	}
121847e946e7SWyllys Ingersoll 
121947e946e7SWyllys Ingersoll 	if ((result = Tspi_Policy_SetSecret(hPolicy, TSS_SECRET_MODE_SHA1,
122047e946e7SWyllys Ingersoll 	    SHA1_DIGEST_LENGTH, passHash))) {
122147e946e7SWyllys Ingersoll 		stlogit("Tspi_Policy_SetSecret: 0x%0x - %s",
122247e946e7SWyllys Ingersoll 		    result, Trspi_Error_String(result));
122347e946e7SWyllys Ingersoll 		return (result);
122447e946e7SWyllys Ingersoll 	}
122547e946e7SWyllys Ingersoll 
122647e946e7SWyllys Ingersoll 	if ((result = Tspi_ChangeAuth(hObjectToChange, hParentObject,
122747e946e7SWyllys Ingersoll 	    hPolicy))) {
122847e946e7SWyllys Ingersoll 		stlogit("Tspi_ChangeAuth: 0x%0x - %s",
122947e946e7SWyllys Ingersoll 		    result, Trspi_Error_String(result));
123047e946e7SWyllys Ingersoll 	}
123147e946e7SWyllys Ingersoll 	/*
123247e946e7SWyllys Ingersoll 	 * Update the PS key by unregistering the key UUID and then
123347e946e7SWyllys Ingersoll 	 * re-registering with the same UUID.  This forces the updated
123447e946e7SWyllys Ingersoll 	 * auth data associated with the key to be stored in PS so
123547e946e7SWyllys Ingersoll 	 * the new PIN can be used next time.
123647e946e7SWyllys Ingersoll 	 */
123747e946e7SWyllys Ingersoll 	if ((result = Tspi_Context_UnregisterKey(hContext,
123847e946e7SWyllys Ingersoll 	    TSS_PS_TYPE_USER, objUUID, &oldkey)))
123947e946e7SWyllys Ingersoll 		stlogit("Tspi_Context_UnregisterKey: 0x%0x - %s",
124047e946e7SWyllys Ingersoll 		    result, Trspi_Error_String(result));
124147e946e7SWyllys Ingersoll 
124247e946e7SWyllys Ingersoll 	if ((result = Tspi_Context_RegisterKey(hContext, hObjectToChange,
124347e946e7SWyllys Ingersoll 	    TSS_PS_TYPE_USER, objUUID, TSS_PS_TYPE_USER, parentUUID)))
124447e946e7SWyllys Ingersoll 		stlogit("Tspi_Context_RegisterKey: 0x%0x - %s",
124547e946e7SWyllys Ingersoll 		    result, Trspi_Error_String(result));
124647e946e7SWyllys Ingersoll 
124747e946e7SWyllys Ingersoll 	return (result);
124847e946e7SWyllys Ingersoll }
124947e946e7SWyllys Ingersoll 
125047e946e7SWyllys Ingersoll static CK_RV
125147e946e7SWyllys Ingersoll token_generate_leaf_key(TSS_HCONTEXT hContext,
125247e946e7SWyllys Ingersoll 	int key_type, CK_CHAR_PTR passHash, TSS_HKEY *phKey)
125347e946e7SWyllys Ingersoll {
125447e946e7SWyllys Ingersoll 	CK_RV		rc = CKR_FUNCTION_FAILED;
125547e946e7SWyllys Ingersoll 	TSS_RESULT	result;
125647e946e7SWyllys Ingersoll 	TSS_HKEY	hParentKey;
125747e946e7SWyllys Ingersoll 	TSS_UUID	newuuid, parentUUID;
125847e946e7SWyllys Ingersoll 	char		*keyid;
125947e946e7SWyllys Ingersoll 	TSS_FLAG	initFlags = TSS_KEY_MIGRATABLE |
126047e946e7SWyllys Ingersoll 	    TSS_KEY_TYPE_BIND | TSS_KEY_SIZE_2048  | TSS_KEY_AUTHORIZATION;
126147e946e7SWyllys Ingersoll 
126247e946e7SWyllys Ingersoll 	switch (key_type) {
126347e946e7SWyllys Ingersoll 		case TPMTOK_PUBLIC_LEAF_KEY:
126447e946e7SWyllys Ingersoll 			hParentKey = hPublicRootKey;
126547e946e7SWyllys Ingersoll 			keyid = TPMTOK_PUBLIC_LEAF_KEY_ID;
126647e946e7SWyllys Ingersoll 			local_uuid_copy(&parentUUID, &publicRootKeyUUID);
126747e946e7SWyllys Ingersoll 			break;
126847e946e7SWyllys Ingersoll 		case TPMTOK_PRIVATE_LEAF_KEY:
126947e946e7SWyllys Ingersoll 			hParentKey = hPrivateRootKey;
127047e946e7SWyllys Ingersoll 			keyid = TPMTOK_PRIVATE_LEAF_KEY_ID;
127147e946e7SWyllys Ingersoll 			local_uuid_copy(&parentUUID, &privateRootKeyUUID);
127247e946e7SWyllys Ingersoll 			break;
127347e946e7SWyllys Ingersoll 		default:
127447e946e7SWyllys Ingersoll 			stlogit("Unknown key type 0x%0x", key_type);
127547e946e7SWyllys Ingersoll 			goto done;
127647e946e7SWyllys Ingersoll 			break;
127747e946e7SWyllys Ingersoll 	}
127847e946e7SWyllys Ingersoll 
127947e946e7SWyllys Ingersoll 	if (result = tss_generate_key(hContext, initFlags, passHash,
128047e946e7SWyllys Ingersoll 	    hParentKey, phKey)) {
128147e946e7SWyllys Ingersoll 		return (rc);
128247e946e7SWyllys Ingersoll 	}
128347e946e7SWyllys Ingersoll 
128447e946e7SWyllys Ingersoll 	/*
128547e946e7SWyllys Ingersoll 	 * - generate newUUID
128647e946e7SWyllys Ingersoll 	 * - Tspi_Context_RegisterKey(hContext, hPrivateRootKey,
128747e946e7SWyllys Ingersoll 	 *   USER, newUUID, USER, parentUUID);
128847e946e7SWyllys Ingersoll 	 * - store newUUID
128947e946e7SWyllys Ingersoll 	 */
129047e946e7SWyllys Ingersoll 	(void) local_uuid_generate(&newuuid);
129147e946e7SWyllys Ingersoll 
129247e946e7SWyllys Ingersoll 	result = Tspi_Context_RegisterKey(hContext, *phKey,
129347e946e7SWyllys Ingersoll 	    TSS_PS_TYPE_USER, newuuid,
129447e946e7SWyllys Ingersoll 	    TSS_PS_TYPE_USER, parentUUID);
129547e946e7SWyllys Ingersoll 	if (result == TSS_SUCCESS) {
129647e946e7SWyllys Ingersoll 		int ret;
129747e946e7SWyllys Ingersoll 		/*
129847e946e7SWyllys Ingersoll 		 * Add the UUID to the token UUID index.
129947e946e7SWyllys Ingersoll 		 */
130047e946e7SWyllys Ingersoll 		ret = add_uuid(keyid, &newuuid);
130147e946e7SWyllys Ingersoll 
130247e946e7SWyllys Ingersoll 		if (ret)
130347e946e7SWyllys Ingersoll 			result = Tspi_Context_UnregisterKey(hContext,
130447e946e7SWyllys Ingersoll 			    TSS_PS_TYPE_USER, newuuid, phKey);
130547e946e7SWyllys Ingersoll 		else
130647e946e7SWyllys Ingersoll 			rc = CKR_OK;
130747e946e7SWyllys Ingersoll 	}
130847e946e7SWyllys Ingersoll 
130947e946e7SWyllys Ingersoll done:
131047e946e7SWyllys Ingersoll 	return (rc);
131147e946e7SWyllys Ingersoll }
131247e946e7SWyllys Ingersoll 
131347e946e7SWyllys Ingersoll /*
131447e946e7SWyllys Ingersoll  * PINs are verified by attempting to bind/unbind random data using a
131547e946e7SWyllys Ingersoll  * TPM resident key that has the PIN being tested assigned as its "secret".
131647e946e7SWyllys Ingersoll  * If the PIN is incorrect, the unbind operation will fail.
131747e946e7SWyllys Ingersoll  */
131847e946e7SWyllys Ingersoll static CK_RV
131947e946e7SWyllys Ingersoll token_verify_pin(TSS_HCONTEXT hContext, TSS_HKEY hKey)
132047e946e7SWyllys Ingersoll {
132147e946e7SWyllys Ingersoll 	TSS_HENCDATA hEncData;
132247e946e7SWyllys Ingersoll 	UINT32 ulUnboundDataLen;
132347e946e7SWyllys Ingersoll 	BYTE *rgbUnboundData = NULL;
132447e946e7SWyllys Ingersoll 	BYTE rgbData[16];
132547e946e7SWyllys Ingersoll 	TSS_RESULT result;
132647e946e7SWyllys Ingersoll 	CK_RV rc = CKR_FUNCTION_FAILED;
132747e946e7SWyllys Ingersoll 
132847e946e7SWyllys Ingersoll 	if ((result = Tspi_Context_CreateObject(hContext,
132947e946e7SWyllys Ingersoll 	    TSS_OBJECT_TYPE_ENCDATA, TSS_ENCDATA_BIND, &hEncData))) {
133047e946e7SWyllys Ingersoll 		stlogit("Tspi_Context_CreateObject: 0x%0x - %s",
133147e946e7SWyllys Ingersoll 		    result, Trspi_Error_String(result));
133247e946e7SWyllys Ingersoll 		goto done;
133347e946e7SWyllys Ingersoll 	}
133447e946e7SWyllys Ingersoll 
133547e946e7SWyllys Ingersoll 	/* Use some random data */
133647e946e7SWyllys Ingersoll 	rc = token_rng(hContext, rgbData, sizeof (rgbData));
133747e946e7SWyllys Ingersoll 	if (rc)
133847e946e7SWyllys Ingersoll 		goto done;
133947e946e7SWyllys Ingersoll 
134047e946e7SWyllys Ingersoll 	if ((result = Tspi_Data_Bind(hEncData, hKey,
134147e946e7SWyllys Ingersoll 	    sizeof (rgbData), rgbData))) {
134247e946e7SWyllys Ingersoll 		stlogit("Tspi_Data_Bind: 0x%0x - %s",
134347e946e7SWyllys Ingersoll 		    result, Trspi_Error_String(result));
134447e946e7SWyllys Ingersoll 		goto done;
134547e946e7SWyllys Ingersoll 	}
134647e946e7SWyllys Ingersoll 
134747e946e7SWyllys Ingersoll 	/* unbind the junk data to test the key's auth data */
134847e946e7SWyllys Ingersoll 	result = Tspi_Data_Unbind(hEncData, hKey, &ulUnboundDataLen,
134947e946e7SWyllys Ingersoll 	    &rgbUnboundData);
1350ab8176c2SWyllys Ingersoll 	if (result == TPM_E_AUTHFAIL) {
135147e946e7SWyllys Ingersoll 		rc = CKR_PIN_INCORRECT;
135247e946e7SWyllys Ingersoll 		stlogit("Tspi_Data_Unbind: 0x%0x - %s",
135347e946e7SWyllys Ingersoll 		    result, Trspi_Error_String(result));
135447e946e7SWyllys Ingersoll 		goto done;
135547e946e7SWyllys Ingersoll 	} else if (result != TSS_SUCCESS) {
135647e946e7SWyllys Ingersoll 		stlogit("Tspi_Data_Unbind: 0x%0x - %s",
135747e946e7SWyllys Ingersoll 		    result, Trspi_Error_String(result));
135847e946e7SWyllys Ingersoll 		rc = CKR_FUNCTION_FAILED;
135947e946e7SWyllys Ingersoll 		goto done;
136047e946e7SWyllys Ingersoll 	}
136147e946e7SWyllys Ingersoll 
136247e946e7SWyllys Ingersoll 	if (memcmp(rgbUnboundData, rgbData, ulUnboundDataLen))
136347e946e7SWyllys Ingersoll 		rc = CKR_PIN_INCORRECT;
136447e946e7SWyllys Ingersoll 	else
136547e946e7SWyllys Ingersoll 		rc = CKR_OK;
136647e946e7SWyllys Ingersoll 
136747e946e7SWyllys Ingersoll done:
136847e946e7SWyllys Ingersoll 	if (rgbUnboundData != NULL)
136947e946e7SWyllys Ingersoll 		Tspi_Context_FreeMemory(hContext, rgbUnboundData);
137047e946e7SWyllys Ingersoll 	Tspi_Context_CloseObject(hContext, hEncData);
137147e946e7SWyllys Ingersoll 	return (rc);
137247e946e7SWyllys Ingersoll }
137347e946e7SWyllys Ingersoll 
137447e946e7SWyllys Ingersoll static CK_RV
137547e946e7SWyllys Ingersoll token_create_private_tree(TSS_HCONTEXT hContext, CK_BYTE *pinHash)
137647e946e7SWyllys Ingersoll {
137747e946e7SWyllys Ingersoll 	CK_RV		rc;
137847e946e7SWyllys Ingersoll 	TSS_RESULT	result;
137947e946e7SWyllys Ingersoll 	int		ret;
138047e946e7SWyllys Ingersoll 	TSS_FLAG initFlags = TSS_KEY_SIZE_2048 |
138147e946e7SWyllys Ingersoll 	    TSS_KEY_NO_AUTHORIZATION | TSS_KEY_TYPE_STORAGE;
138247e946e7SWyllys Ingersoll 	TSS_UUID SRK_UUID = TSS_UUID_SRK;
138347e946e7SWyllys Ingersoll 	TSS_HKEY hSRK;
138447e946e7SWyllys Ingersoll 
138547e946e7SWyllys Ingersoll 	if (token_load_srk(hContext, &hSRK))
138647e946e7SWyllys Ingersoll 		return (CKR_FUNCTION_FAILED);
138747e946e7SWyllys Ingersoll 
138847e946e7SWyllys Ingersoll 	/*
138947e946e7SWyllys Ingersoll 	 * - create UUID privateRootKeyUUID
139047e946e7SWyllys Ingersoll 	 * - Tspi_Context_RegisterKey(hContext, hPrivateRootKey,
139147e946e7SWyllys Ingersoll 	 *   USER, privateRootKeyUUID, system, UUID_SRK);
139247e946e7SWyllys Ingersoll 	 * - store privateRootKeyUUID in users private token space.
139347e946e7SWyllys Ingersoll 	 */
139447e946e7SWyllys Ingersoll 	if ((result = tss_generate_key(hContext, initFlags, NULL, hSRK,
139547e946e7SWyllys Ingersoll 	    &hPrivateRootKey))) {
139647e946e7SWyllys Ingersoll 		return (result);
139747e946e7SWyllys Ingersoll 	}
139847e946e7SWyllys Ingersoll 	if (local_uuid_is_null(&privateRootKeyUUID))
139947e946e7SWyllys Ingersoll 		local_uuid_generate(&privateRootKeyUUID);
140047e946e7SWyllys Ingersoll 
140147e946e7SWyllys Ingersoll 	result = Tspi_Context_RegisterKey(hContext, hPrivateRootKey,
140247e946e7SWyllys Ingersoll 	    TSS_PS_TYPE_USER, privateRootKeyUUID,
140347e946e7SWyllys Ingersoll 	    TSS_PS_TYPE_SYSTEM, SRK_UUID);
140447e946e7SWyllys Ingersoll 
140547e946e7SWyllys Ingersoll 	if (result) {
140647e946e7SWyllys Ingersoll 		local_uuid_clear(&privateRootKeyUUID);
140747e946e7SWyllys Ingersoll 		return (result);
140847e946e7SWyllys Ingersoll 	}
140947e946e7SWyllys Ingersoll 
141047e946e7SWyllys Ingersoll 	ret = add_uuid(TPMTOK_PRIVATE_ROOT_KEY_ID, &privateRootKeyUUID);
141147e946e7SWyllys Ingersoll 	if (ret) {
141247e946e7SWyllys Ingersoll 		result = Tspi_Context_UnregisterKey(hContext,
141347e946e7SWyllys Ingersoll 		    TSS_PS_TYPE_USER, privateRootKeyUUID,
141447e946e7SWyllys Ingersoll 		    &hPrivateRootKey);
141547e946e7SWyllys Ingersoll 		return (CKR_FUNCTION_FAILED);
141647e946e7SWyllys Ingersoll 	}
141747e946e7SWyllys Ingersoll 
141847e946e7SWyllys Ingersoll 	if ((result = Tspi_Key_LoadKey(hPrivateRootKey, hSRK))) {
141947e946e7SWyllys Ingersoll 		stlogit("Tspi_Key_LoadKey: 0x%0x - %s",
142047e946e7SWyllys Ingersoll 		    result, Trspi_Error_String(result));
142147e946e7SWyllys Ingersoll 		Tspi_Context_CloseObject(hContext, hPrivateRootKey);
142247e946e7SWyllys Ingersoll 
142347e946e7SWyllys Ingersoll 		(void) remove_uuid(TPMTOK_PRIVATE_ROOT_KEY_ID);
142447e946e7SWyllys Ingersoll 		local_uuid_clear(&privateRootKeyUUID);
142547e946e7SWyllys Ingersoll 
142647e946e7SWyllys Ingersoll 		hPrivateRootKey = NULL_HKEY;
142747e946e7SWyllys Ingersoll 		return (CKR_FUNCTION_FAILED);
142847e946e7SWyllys Ingersoll 	}
142947e946e7SWyllys Ingersoll 
143047e946e7SWyllys Ingersoll 
143147e946e7SWyllys Ingersoll 	/* generate the private leaf key */
143247e946e7SWyllys Ingersoll 	if ((rc = token_generate_leaf_key(hContext,
143347e946e7SWyllys Ingersoll 	    TPMTOK_PRIVATE_LEAF_KEY,
143447e946e7SWyllys Ingersoll 	    pinHash, &hPrivateLeafKey))) {
143547e946e7SWyllys Ingersoll 		return (rc);
143647e946e7SWyllys Ingersoll 	}
143747e946e7SWyllys Ingersoll 
143847e946e7SWyllys Ingersoll 	if ((result = Tspi_Key_LoadKey(hPrivateLeafKey, hPrivateRootKey))) {
143947e946e7SWyllys Ingersoll 		stlogit("Tspi_Key_LoadKey: 0x%0x - %s",
144047e946e7SWyllys Ingersoll 		    result, Trspi_Error_String(result));
144147e946e7SWyllys Ingersoll 
144247e946e7SWyllys Ingersoll 		(void) Tspi_Context_UnregisterKey(hContext,
144347e946e7SWyllys Ingersoll 		    TSS_PS_TYPE_USER, privateLeafKeyUUID,
144447e946e7SWyllys Ingersoll 		    &hPrivateLeafKey);
144547e946e7SWyllys Ingersoll 		(void) remove_uuid(TPMTOK_PRIVATE_LEAF_KEY_ID);
144647e946e7SWyllys Ingersoll 		local_uuid_clear(&privateLeafKeyUUID);
144747e946e7SWyllys Ingersoll 
144847e946e7SWyllys Ingersoll 		(void) Tspi_Context_UnregisterKey(hContext,
144947e946e7SWyllys Ingersoll 		    TSS_PS_TYPE_USER, privateRootKeyUUID,
145047e946e7SWyllys Ingersoll 		    &hPrivateRootKey);
145147e946e7SWyllys Ingersoll 		(void) remove_uuid(TPMTOK_PRIVATE_ROOT_KEY_ID);
145247e946e7SWyllys Ingersoll 		local_uuid_clear(&privateRootKeyUUID);
145347e946e7SWyllys Ingersoll 
145447e946e7SWyllys Ingersoll 		Tspi_Context_CloseObject(hContext, hPrivateRootKey);
145547e946e7SWyllys Ingersoll 		hPrivateRootKey = NULL_HKEY;
145647e946e7SWyllys Ingersoll 
145747e946e7SWyllys Ingersoll 		Tspi_Context_CloseObject(hContext, hPrivateLeafKey);
145847e946e7SWyllys Ingersoll 		hPrivateRootKey = NULL_HKEY;
145947e946e7SWyllys Ingersoll 
146047e946e7SWyllys Ingersoll 		return (CKR_FUNCTION_FAILED);
146147e946e7SWyllys Ingersoll 	}
146247e946e7SWyllys Ingersoll 	return (rc);
146347e946e7SWyllys Ingersoll }
146447e946e7SWyllys Ingersoll 
146547e946e7SWyllys Ingersoll static CK_RV
146647e946e7SWyllys Ingersoll token_create_public_tree(TSS_HCONTEXT hContext, CK_BYTE *pinHash)
146747e946e7SWyllys Ingersoll {
146847e946e7SWyllys Ingersoll 	CK_RV		rc;
146947e946e7SWyllys Ingersoll 	TSS_RESULT	result;
147047e946e7SWyllys Ingersoll 	int		ret;
147147e946e7SWyllys Ingersoll 	TSS_FLAG initFlags = TSS_KEY_SIZE_2048 |
147247e946e7SWyllys Ingersoll 	    TSS_KEY_NO_AUTHORIZATION | TSS_KEY_TYPE_STORAGE;
147347e946e7SWyllys Ingersoll 	TSS_UUID srk_uuid = TSS_UUID_SRK;
147447e946e7SWyllys Ingersoll 	TSS_HKEY hSRK;
147547e946e7SWyllys Ingersoll 
147647e946e7SWyllys Ingersoll 	if (token_load_srk(hContext, &hSRK))
147747e946e7SWyllys Ingersoll 		return (CKR_FUNCTION_FAILED);
147847e946e7SWyllys Ingersoll 
147947e946e7SWyllys Ingersoll 	/*
148047e946e7SWyllys Ingersoll 	 * - create publicRootKeyUUID
148147e946e7SWyllys Ingersoll 	 * - Tspi_Context_RegisterKey(hContext, hPublicRootKey,
148247e946e7SWyllys Ingersoll 	 *   USER, publicRootKeyUUID, system, UUID_SRK);
148347e946e7SWyllys Ingersoll 	 * - store publicRootKeyUUID in users private token space.
148447e946e7SWyllys Ingersoll 	 */
148547e946e7SWyllys Ingersoll 	if ((result = tss_generate_key(hContext, initFlags, NULL, hSRK,
148647e946e7SWyllys Ingersoll 	    &hPublicRootKey))) {
148747e946e7SWyllys Ingersoll 		return (CKR_FUNCTION_FAILED);
148847e946e7SWyllys Ingersoll 	}
148947e946e7SWyllys Ingersoll 	if (local_uuid_is_null(&publicRootKeyUUID))
149047e946e7SWyllys Ingersoll 		local_uuid_generate(&publicRootKeyUUID);
149147e946e7SWyllys Ingersoll 
149247e946e7SWyllys Ingersoll 	result = Tspi_Context_RegisterKey(hContext, hPublicRootKey,
149347e946e7SWyllys Ingersoll 	    TSS_PS_TYPE_USER, publicRootKeyUUID,
149447e946e7SWyllys Ingersoll 	    TSS_PS_TYPE_SYSTEM, srk_uuid);
149547e946e7SWyllys Ingersoll 
149647e946e7SWyllys Ingersoll 	if (result) {
149747e946e7SWyllys Ingersoll 		local_uuid_clear(&publicRootKeyUUID);
149847e946e7SWyllys Ingersoll 		return (CKR_FUNCTION_FAILED);
149947e946e7SWyllys Ingersoll 	}
150047e946e7SWyllys Ingersoll 
150147e946e7SWyllys Ingersoll 	ret = add_uuid(TPMTOK_PUBLIC_ROOT_KEY_ID, &publicRootKeyUUID);
150247e946e7SWyllys Ingersoll 	if (ret) {
150347e946e7SWyllys Ingersoll 		result = Tspi_Context_UnregisterKey(hContext,
150447e946e7SWyllys Ingersoll 		    TSS_PS_TYPE_USER, publicRootKeyUUID,
150547e946e7SWyllys Ingersoll 		    &hPublicRootKey);
150647e946e7SWyllys Ingersoll 		/* does result matter here? */
150747e946e7SWyllys Ingersoll 		return (CKR_FUNCTION_FAILED);
150847e946e7SWyllys Ingersoll 	}
150947e946e7SWyllys Ingersoll 
151047e946e7SWyllys Ingersoll 	/* Load the newly created publicRootKey into the TPM using the SRK */
151147e946e7SWyllys Ingersoll 	if ((result = Tspi_Key_LoadKey(hPublicRootKey, hSRK))) {
151247e946e7SWyllys Ingersoll 		stlogit("Tspi_Key_LoadKey: 0x%x - %s", result,
151347e946e7SWyllys Ingersoll 		    Trspi_Error_String(result));
151447e946e7SWyllys Ingersoll 		Tspi_Context_CloseObject(hContext, hPublicRootKey);
151547e946e7SWyllys Ingersoll 		hPublicRootKey = NULL_HKEY;
151647e946e7SWyllys Ingersoll 		return (CKR_FUNCTION_FAILED);
151747e946e7SWyllys Ingersoll 	}
151847e946e7SWyllys Ingersoll 
151947e946e7SWyllys Ingersoll 	/* create the SO's leaf key */
152047e946e7SWyllys Ingersoll 	if ((rc = token_generate_leaf_key(hContext, TPMTOK_PUBLIC_LEAF_KEY,
152147e946e7SWyllys Ingersoll 	    pinHash, &hPublicLeafKey))) {
152247e946e7SWyllys Ingersoll 		return (rc);
152347e946e7SWyllys Ingersoll 	}
152447e946e7SWyllys Ingersoll 
152547e946e7SWyllys Ingersoll 	if ((result = Tspi_Key_LoadKey(hPublicLeafKey, hPublicRootKey))) {
152647e946e7SWyllys Ingersoll 		stlogit("Tspi_Key_LoadKey: 0x%0x - %s",
152747e946e7SWyllys Ingersoll 		    result, Trspi_Error_String(result));
152847e946e7SWyllys Ingersoll 
152947e946e7SWyllys Ingersoll 		/* Unregister keys and clear UUIDs */
153047e946e7SWyllys Ingersoll 		(void) Tspi_Context_UnregisterKey(hContext,
153147e946e7SWyllys Ingersoll 		    TSS_PS_TYPE_USER, publicLeafKeyUUID,
153247e946e7SWyllys Ingersoll 		    &hPublicLeafKey);
153347e946e7SWyllys Ingersoll 		(void) remove_uuid(TPMTOK_PUBLIC_LEAF_KEY_ID);
153447e946e7SWyllys Ingersoll 
153547e946e7SWyllys Ingersoll 		(void) Tspi_Context_UnregisterKey(hContext,
153647e946e7SWyllys Ingersoll 		    TSS_PS_TYPE_USER, publicRootKeyUUID,
153747e946e7SWyllys Ingersoll 		    &hPublicRootKey);
153847e946e7SWyllys Ingersoll 		(void) remove_uuid(TPMTOK_PUBLIC_ROOT_KEY_ID);
153947e946e7SWyllys Ingersoll 
154047e946e7SWyllys Ingersoll 		Tspi_Context_CloseObject(hContext, hPublicRootKey);
154147e946e7SWyllys Ingersoll 		hPublicRootKey = NULL_HKEY;
154247e946e7SWyllys Ingersoll 
154347e946e7SWyllys Ingersoll 		Tspi_Context_CloseObject(hContext, hPublicLeafKey);
154447e946e7SWyllys Ingersoll 		hPublicLeafKey = NULL_HKEY;
154547e946e7SWyllys Ingersoll 
154647e946e7SWyllys Ingersoll 		return (CKR_FUNCTION_FAILED);
154747e946e7SWyllys Ingersoll 	}
154847e946e7SWyllys Ingersoll 
154947e946e7SWyllys Ingersoll 	return (rc);
155047e946e7SWyllys Ingersoll }
155147e946e7SWyllys Ingersoll 
155247e946e7SWyllys Ingersoll CK_RV
155347e946e7SWyllys Ingersoll token_specific_login(
155447e946e7SWyllys Ingersoll 	TSS_HCONTEXT hContext,
155547e946e7SWyllys Ingersoll 	CK_USER_TYPE userType,
155647e946e7SWyllys Ingersoll 	CK_CHAR_PTR pPin,
155747e946e7SWyllys Ingersoll 	CK_ULONG ulPinLen)
155847e946e7SWyllys Ingersoll {
155947e946e7SWyllys Ingersoll 	CK_RV rc;
156047e946e7SWyllys Ingersoll 	CK_BYTE hash_sha[SHA1_DIGEST_LENGTH];
156147e946e7SWyllys Ingersoll 	TSS_RESULT result;
156247e946e7SWyllys Ingersoll 	TSS_HKEY hSRK;
156347e946e7SWyllys Ingersoll 
156447e946e7SWyllys Ingersoll 	/* Make sure the SRK is loaded into the TPM */
156547e946e7SWyllys Ingersoll 	if ((result = token_load_srk(hContext, &hSRK))) {
156647e946e7SWyllys Ingersoll 		return (CKR_FUNCTION_FAILED);
156747e946e7SWyllys Ingersoll 	}
156847e946e7SWyllys Ingersoll 
156947e946e7SWyllys Ingersoll 	if ((rc = compute_sha(pPin, ulPinLen, hash_sha))) {
157047e946e7SWyllys Ingersoll 		return (CKR_FUNCTION_FAILED);
157147e946e7SWyllys Ingersoll 	}
157247e946e7SWyllys Ingersoll 
157347e946e7SWyllys Ingersoll 	if (userType == CKU_USER) {
157447e946e7SWyllys Ingersoll 		/*
157547e946e7SWyllys Ingersoll 		 * If the public root key doesn't exist yet,
157647e946e7SWyllys Ingersoll 		 * the SO hasn't init'd the token.
157747e946e7SWyllys Ingersoll 		 */
157847e946e7SWyllys Ingersoll 		if ((result = token_load_public_root_key(hContext))) {
157947e946e7SWyllys Ingersoll 			if (result == TPM_E_DECRYPT_ERROR) {
158047e946e7SWyllys Ingersoll 				return (CKR_USER_PIN_NOT_INITIALIZED);
158147e946e7SWyllys Ingersoll 			}
158247e946e7SWyllys Ingersoll 		}
158347e946e7SWyllys Ingersoll 
158447e946e7SWyllys Ingersoll 		/*
158547e946e7SWyllys Ingersoll 		 * - find privateRootKeyUUID
158647e946e7SWyllys Ingersoll 		 * - load by UUID (SRK parent)
158747e946e7SWyllys Ingersoll 		 */
158847e946e7SWyllys Ingersoll 		if (local_uuid_is_null(&privateRootKeyUUID) &&
158947e946e7SWyllys Ingersoll 		    find_uuid(TPMTOK_PRIVATE_ROOT_KEY_ID,
159047e946e7SWyllys Ingersoll 		    &privateRootKeyUUID)) {
159147e946e7SWyllys Ingersoll 				if (memcmp(hash_sha,
159247e946e7SWyllys Ingersoll 				    default_user_pin_sha,
159347e946e7SWyllys Ingersoll 				    SHA1_DIGEST_LENGTH))
159447e946e7SWyllys Ingersoll 					return (CKR_PIN_INCORRECT);
159547e946e7SWyllys Ingersoll 
159647e946e7SWyllys Ingersoll 				not_initialized = 1;
159747e946e7SWyllys Ingersoll 				return (CKR_OK);
159847e946e7SWyllys Ingersoll 		}
159947e946e7SWyllys Ingersoll 
160047e946e7SWyllys Ingersoll 		if ((rc = verify_user_pin(hContext, hash_sha))) {
160147e946e7SWyllys Ingersoll 			return (rc);
160247e946e7SWyllys Ingersoll 		}
160347e946e7SWyllys Ingersoll 
160447e946e7SWyllys Ingersoll 		(void) memcpy(current_user_pin_sha, hash_sha,
160547e946e7SWyllys Ingersoll 		    SHA1_DIGEST_LENGTH);
160647e946e7SWyllys Ingersoll 
160747e946e7SWyllys Ingersoll 		rc = load_private_token_objects(hContext);
160847e946e7SWyllys Ingersoll 		if (rc == CKR_OK) {
160947e946e7SWyllys Ingersoll 			(void) XProcLock(xproclock);
161047e946e7SWyllys Ingersoll 			global_shm->priv_loaded = TRUE;
161147e946e7SWyllys Ingersoll 			(void) XProcUnLock(xproclock);
161247e946e7SWyllys Ingersoll 		}
161347e946e7SWyllys Ingersoll 	} else {
161447e946e7SWyllys Ingersoll 		/*
161547e946e7SWyllys Ingersoll 		 * SO login logic:
161647e946e7SWyllys Ingersoll 		 *
161747e946e7SWyllys Ingersoll 		 * - find publicRootKey UUID
161847e946e7SWyllys Ingersoll 		 * - load by UUID wrap with hSRK from above
161947e946e7SWyllys Ingersoll 		 */
162047e946e7SWyllys Ingersoll 		if (local_uuid_is_null(&publicRootKeyUUID) &&
162147e946e7SWyllys Ingersoll 		    find_uuid(TPMTOK_PUBLIC_ROOT_KEY_ID,
162247e946e7SWyllys Ingersoll 		    &publicRootKeyUUID)) {
162347e946e7SWyllys Ingersoll 				if (memcmp(hash_sha,
162447e946e7SWyllys Ingersoll 				    default_so_pin_sha,
162547e946e7SWyllys Ingersoll 				    SHA1_DIGEST_LENGTH))
162647e946e7SWyllys Ingersoll 					return (CKR_PIN_INCORRECT);
162747e946e7SWyllys Ingersoll 
162847e946e7SWyllys Ingersoll 				not_initialized = 1;
162947e946e7SWyllys Ingersoll 				return (CKR_OK);
163047e946e7SWyllys Ingersoll 
163147e946e7SWyllys Ingersoll 		}
163247e946e7SWyllys Ingersoll 		if (hPublicRootKey == NULL_HKEY) {
163347e946e7SWyllys Ingersoll 			result = tss_find_and_load_key(
163447e946e7SWyllys Ingersoll 			    hContext,
163547e946e7SWyllys Ingersoll 			    TPMTOK_PUBLIC_ROOT_KEY_ID,
163647e946e7SWyllys Ingersoll 			    &publicRootKeyUUID, hSRK, NULL,
163747e946e7SWyllys Ingersoll 			    &hPublicRootKey);
163847e946e7SWyllys Ingersoll 
163947e946e7SWyllys Ingersoll 			if (result)
164047e946e7SWyllys Ingersoll 				return (CKR_FUNCTION_FAILED);
164147e946e7SWyllys Ingersoll 		}
164247e946e7SWyllys Ingersoll 
164347e946e7SWyllys Ingersoll 		/* find, load the public leaf key */
164447e946e7SWyllys Ingersoll 		if (hPublicLeafKey == NULL_HKEY) {
164547e946e7SWyllys Ingersoll 			result = tss_find_and_load_key(
164647e946e7SWyllys Ingersoll 			    hContext,
164747e946e7SWyllys Ingersoll 			    TPMTOK_PUBLIC_LEAF_KEY_ID,
164847e946e7SWyllys Ingersoll 			    &publicLeafKeyUUID, hPublicRootKey, hash_sha,
164947e946e7SWyllys Ingersoll 			    &hPublicLeafKey);
165047e946e7SWyllys Ingersoll 			if (result)
165147e946e7SWyllys Ingersoll 				return (CKR_FUNCTION_FAILED);
165247e946e7SWyllys Ingersoll 		}
165347e946e7SWyllys Ingersoll 
165447e946e7SWyllys Ingersoll 		if ((rc = token_verify_pin(hContext, hPublicLeafKey))) {
165547e946e7SWyllys Ingersoll 			return (rc);
165647e946e7SWyllys Ingersoll 		}
165747e946e7SWyllys Ingersoll 
165847e946e7SWyllys Ingersoll 		(void) memcpy(current_so_pin_sha, hash_sha, SHA1_DIGEST_LENGTH);
165947e946e7SWyllys Ingersoll 	}
166047e946e7SWyllys Ingersoll 
166147e946e7SWyllys Ingersoll 	return (rc);
166247e946e7SWyllys Ingersoll }
166347e946e7SWyllys Ingersoll 
166447e946e7SWyllys Ingersoll CK_RV
166547e946e7SWyllys Ingersoll token_specific_logout(TSS_HCONTEXT hContext)
166647e946e7SWyllys Ingersoll {
166747e946e7SWyllys Ingersoll 	if (hPrivateLeafKey != NULL_HKEY) {
166847e946e7SWyllys Ingersoll 		Tspi_Key_UnloadKey(hPrivateLeafKey);
166947e946e7SWyllys Ingersoll 		hPrivateLeafKey = NULL_HKEY;
167047e946e7SWyllys Ingersoll 	} else if (hPublicLeafKey != NULL_HKEY) {
167147e946e7SWyllys Ingersoll 		Tspi_Key_UnloadKey(hPublicLeafKey);
167247e946e7SWyllys Ingersoll 		hPublicLeafKey = NULL_HKEY;
167347e946e7SWyllys Ingersoll 	}
167447e946e7SWyllys Ingersoll 
167547e946e7SWyllys Ingersoll 	local_uuid_clear(&publicRootKeyUUID);
167647e946e7SWyllys Ingersoll 	local_uuid_clear(&publicLeafKeyUUID);
167747e946e7SWyllys Ingersoll 	local_uuid_clear(&privateRootKeyUUID);
167847e946e7SWyllys Ingersoll 	local_uuid_clear(&privateLeafKeyUUID);
167947e946e7SWyllys Ingersoll 
168047e946e7SWyllys Ingersoll 	(void) memset(current_so_pin_sha, 0, SHA1_DIGEST_LENGTH);
168147e946e7SWyllys Ingersoll 	(void) memset(current_user_pin_sha, 0, SHA1_DIGEST_LENGTH);
168247e946e7SWyllys Ingersoll 
168347e946e7SWyllys Ingersoll 	(void) object_mgr_purge_private_token_objects(hContext);
168447e946e7SWyllys Ingersoll 
168547e946e7SWyllys Ingersoll 	return (CKR_OK);
168647e946e7SWyllys Ingersoll }
168747e946e7SWyllys Ingersoll 
168847e946e7SWyllys Ingersoll /*ARGSUSED*/
168947e946e7SWyllys Ingersoll CK_RV
169047e946e7SWyllys Ingersoll token_specific_init_pin(TSS_HCONTEXT hContext,
169147e946e7SWyllys Ingersoll 	CK_CHAR_PTR pPin, CK_ULONG ulPinLen)
169247e946e7SWyllys Ingersoll {
169347e946e7SWyllys Ingersoll 	/*
169447e946e7SWyllys Ingersoll 	 * Since the SO must log in before calling C_InitPIN, we will
169547e946e7SWyllys Ingersoll 	 * be able to return (CKR_OK) automatically here.
169647e946e7SWyllys Ingersoll 	 * This is because the USER key structure is created at the
169747e946e7SWyllys Ingersoll 	 * time of her first login, not at C_InitPIN time.
169847e946e7SWyllys Ingersoll 	 */
169947e946e7SWyllys Ingersoll 	return (CKR_OK);
170047e946e7SWyllys Ingersoll }
170147e946e7SWyllys Ingersoll 
170247e946e7SWyllys Ingersoll static CK_RV
170347e946e7SWyllys Ingersoll check_pin_properties(CK_USER_TYPE userType, CK_BYTE *pinHash,
170447e946e7SWyllys Ingersoll 	CK_ULONG ulPinLen)
170547e946e7SWyllys Ingersoll {
170647e946e7SWyllys Ingersoll 	/* make sure the new PIN is different */
170747e946e7SWyllys Ingersoll 	if (userType == CKU_USER) {
170847e946e7SWyllys Ingersoll 		if (!memcmp(pinHash, default_user_pin_sha,
170947e946e7SWyllys Ingersoll 		    SHA1_DIGEST_LENGTH)) {
171047e946e7SWyllys Ingersoll 			LogError1("new PIN must not be the default");
171147e946e7SWyllys Ingersoll 			return (CKR_PIN_INVALID);
171247e946e7SWyllys Ingersoll 		}
171347e946e7SWyllys Ingersoll 	} else {
171447e946e7SWyllys Ingersoll 		if (!memcmp(pinHash, default_so_pin_sha,
171547e946e7SWyllys Ingersoll 		    SHA1_DIGEST_LENGTH)) {
171647e946e7SWyllys Ingersoll 			LogError1("new PIN must not be the default");
171747e946e7SWyllys Ingersoll 			return (CKR_PIN_INVALID);
171847e946e7SWyllys Ingersoll 		}
171947e946e7SWyllys Ingersoll 	}
172047e946e7SWyllys Ingersoll 
172147e946e7SWyllys Ingersoll 	if (ulPinLen > MAX_PIN_LEN || ulPinLen < MIN_PIN_LEN) {
172247e946e7SWyllys Ingersoll 		LogError1("New PIN is out of size range");
172347e946e7SWyllys Ingersoll 		return (CKR_PIN_LEN_RANGE);
172447e946e7SWyllys Ingersoll 	}
172547e946e7SWyllys Ingersoll 
172647e946e7SWyllys Ingersoll 	return (CKR_OK);
172747e946e7SWyllys Ingersoll }
172847e946e7SWyllys Ingersoll 
172947e946e7SWyllys Ingersoll /*
173047e946e7SWyllys Ingersoll  * This function is called from set_pin only, where a non-logged-in public
173147e946e7SWyllys Ingersoll  * session can provide the user pin which must be verified. This function
173247e946e7SWyllys Ingersoll  * assumes that the pin has already been set once, so there's no migration
173347e946e7SWyllys Ingersoll  * path option or checking of the default user pin.
173447e946e7SWyllys Ingersoll  */
173547e946e7SWyllys Ingersoll static CK_RV
173647e946e7SWyllys Ingersoll verify_user_pin(TSS_HCONTEXT hContext, CK_BYTE *hash_sha)
173747e946e7SWyllys Ingersoll {
173847e946e7SWyllys Ingersoll 	CK_RV rc;
173947e946e7SWyllys Ingersoll 	TSS_RESULT result;
174047e946e7SWyllys Ingersoll 	TSS_HKEY hSRK;
174147e946e7SWyllys Ingersoll 
174247e946e7SWyllys Ingersoll 	if (token_load_srk(hContext, &hSRK))
174347e946e7SWyllys Ingersoll 		return (CKR_FUNCTION_FAILED);
174447e946e7SWyllys Ingersoll 
174547e946e7SWyllys Ingersoll 	/*
174647e946e7SWyllys Ingersoll 	 * Verify the user by loading the privateLeafKey
174747e946e7SWyllys Ingersoll 	 * into the TPM (if it's not already) and then
174847e946e7SWyllys Ingersoll 	 * call the verify_pin operation.
174947e946e7SWyllys Ingersoll 	 *
175047e946e7SWyllys Ingersoll 	 * The hashed PIN is assigned to the private leaf key.
175147e946e7SWyllys Ingersoll 	 * If it is incorrect (not the same as the one originally
175247e946e7SWyllys Ingersoll 	 * used when the key was created), the verify operation
175347e946e7SWyllys Ingersoll 	 * will fail.
175447e946e7SWyllys Ingersoll 	 */
175547e946e7SWyllys Ingersoll 	if (hPrivateRootKey == NULL_HKEY) {
175647e946e7SWyllys Ingersoll 		result = tss_find_and_load_key(
175747e946e7SWyllys Ingersoll 		    hContext,
175847e946e7SWyllys Ingersoll 		    TPMTOK_PRIVATE_ROOT_KEY_ID,
175947e946e7SWyllys Ingersoll 		    &privateRootKeyUUID, hSRK, NULL, &hPrivateRootKey);
176047e946e7SWyllys Ingersoll 		if (result)
176147e946e7SWyllys Ingersoll 			return (CKR_FUNCTION_FAILED);
176247e946e7SWyllys Ingersoll 	}
176347e946e7SWyllys Ingersoll 
176447e946e7SWyllys Ingersoll 	if (hPrivateLeafKey == NULL_HKEY) {
176547e946e7SWyllys Ingersoll 		result = tss_find_and_load_key(
176647e946e7SWyllys Ingersoll 		    hContext,
176747e946e7SWyllys Ingersoll 		    TPMTOK_PRIVATE_LEAF_KEY_ID,
176847e946e7SWyllys Ingersoll 		    &privateLeafKeyUUID, hPrivateRootKey, hash_sha,
176947e946e7SWyllys Ingersoll 		    &hPrivateLeafKey);
177047e946e7SWyllys Ingersoll 
177147e946e7SWyllys Ingersoll 		if (result)
177247e946e7SWyllys Ingersoll 			return (CKR_FUNCTION_FAILED);
177347e946e7SWyllys Ingersoll 	}
177447e946e7SWyllys Ingersoll 
177547e946e7SWyllys Ingersoll 	/*
177647e946e7SWyllys Ingersoll 	 * Verify that the PIN is correct by attempting to wrap/unwrap some
177747e946e7SWyllys Ingersoll 	 * random data.
177847e946e7SWyllys Ingersoll 	 */
177947e946e7SWyllys Ingersoll 	if ((rc = token_verify_pin(hContext, hPrivateLeafKey))) {
178047e946e7SWyllys Ingersoll 		return (rc);
178147e946e7SWyllys Ingersoll 	}
178247e946e7SWyllys Ingersoll 
178347e946e7SWyllys Ingersoll 	return (CKR_OK);
178447e946e7SWyllys Ingersoll }
178547e946e7SWyllys Ingersoll 
178647e946e7SWyllys Ingersoll CK_RV
178747e946e7SWyllys Ingersoll token_specific_set_pin(ST_SESSION_HANDLE session,
178847e946e7SWyllys Ingersoll 	CK_CHAR_PTR pOldPin, CK_ULONG ulOldPinLen,
178947e946e7SWyllys Ingersoll 	CK_CHAR_PTR pNewPin, CK_ULONG ulNewPinLen)
179047e946e7SWyllys Ingersoll {
179147e946e7SWyllys Ingersoll 	SESSION		*sess = session_mgr_find(session.sessionh);
179247e946e7SWyllys Ingersoll 	CK_BYTE		oldpin_hash[SHA1_DIGEST_LENGTH];
179347e946e7SWyllys Ingersoll 	CK_BYTE		newpin_hash[SHA1_DIGEST_LENGTH];
179447e946e7SWyllys Ingersoll 	CK_RV		rc;
179547e946e7SWyllys Ingersoll 	TSS_HKEY	hSRK;
179647e946e7SWyllys Ingersoll 
179747e946e7SWyllys Ingersoll 	if (!sess) {
179847e946e7SWyllys Ingersoll 		return (CKR_SESSION_HANDLE_INVALID);
179947e946e7SWyllys Ingersoll 	}
180047e946e7SWyllys Ingersoll 
180147e946e7SWyllys Ingersoll 	if ((rc = compute_sha(pOldPin, ulOldPinLen, oldpin_hash))) {
180247e946e7SWyllys Ingersoll 		return (CKR_FUNCTION_FAILED);
180347e946e7SWyllys Ingersoll 	}
180447e946e7SWyllys Ingersoll 	if ((rc = compute_sha(pNewPin, ulNewPinLen, newpin_hash))) {
180547e946e7SWyllys Ingersoll 		return (CKR_FUNCTION_FAILED);
180647e946e7SWyllys Ingersoll 	}
180747e946e7SWyllys Ingersoll 
180847e946e7SWyllys Ingersoll 	if (token_load_srk(sess->hContext, &hSRK)) {
180947e946e7SWyllys Ingersoll 		return (CKR_FUNCTION_FAILED);
181047e946e7SWyllys Ingersoll 	}
181147e946e7SWyllys Ingersoll 
181247e946e7SWyllys Ingersoll 	/*
181347e946e7SWyllys Ingersoll 	 * From the PKCS#11 2.20 spec: "C_SetPIN modifies the PIN of
181447e946e7SWyllys Ingersoll 	 * the user that is currently logged in, or the CKU_USER PIN
181547e946e7SWyllys Ingersoll 	 * if the session is not logged in."
181647e946e7SWyllys Ingersoll 	 * A non R/W session fails with CKR_SESSION_READ_ONLY.
181747e946e7SWyllys Ingersoll 	 */
181847e946e7SWyllys Ingersoll 	if (sess->session_info.state == CKS_RW_USER_FUNCTIONS ||
181947e946e7SWyllys Ingersoll 	    sess->session_info.state == CKS_RW_PUBLIC_SESSION) {
182047e946e7SWyllys Ingersoll 		if (not_initialized) {
182147e946e7SWyllys Ingersoll 			if (memcmp(oldpin_hash, default_user_pin_sha,
182247e946e7SWyllys Ingersoll 			    SHA1_DIGEST_LENGTH)) {
182347e946e7SWyllys Ingersoll 				return (CKR_PIN_INCORRECT);
182447e946e7SWyllys Ingersoll 			}
182547e946e7SWyllys Ingersoll 
182647e946e7SWyllys Ingersoll 			if ((rc = check_pin_properties(CKU_USER, newpin_hash,
182747e946e7SWyllys Ingersoll 			    ulNewPinLen))) {
182847e946e7SWyllys Ingersoll 				return (rc);
182947e946e7SWyllys Ingersoll 			}
183047e946e7SWyllys Ingersoll 
183147e946e7SWyllys Ingersoll 			if ((rc = token_create_private_tree(sess->hContext,
183247e946e7SWyllys Ingersoll 			    newpin_hash))) {
183347e946e7SWyllys Ingersoll 				return (CKR_FUNCTION_FAILED);
183447e946e7SWyllys Ingersoll 			}
183547e946e7SWyllys Ingersoll 
183647e946e7SWyllys Ingersoll 			nv_token_data->token_info.flags &=
183747e946e7SWyllys Ingersoll 			    ~(CKF_USER_PIN_TO_BE_CHANGED);
183847e946e7SWyllys Ingersoll 			nv_token_data->token_info.flags |=
183947e946e7SWyllys Ingersoll 			    CKF_USER_PIN_INITIALIZED;
184047e946e7SWyllys Ingersoll 
184147e946e7SWyllys Ingersoll 			nv_token_data->token_info.flags &=
184247e946e7SWyllys Ingersoll 			    ~(CKF_USER_PIN_TO_BE_CHANGED);
184347e946e7SWyllys Ingersoll 			nv_token_data->token_info.flags |=
184447e946e7SWyllys Ingersoll 			    CKF_USER_PIN_INITIALIZED;
184547e946e7SWyllys Ingersoll 
184647e946e7SWyllys Ingersoll 			return (save_token_data(nv_token_data));
184747e946e7SWyllys Ingersoll 		}
184847e946e7SWyllys Ingersoll 
184947e946e7SWyllys Ingersoll 		if (sess->session_info.state == CKS_RW_USER_FUNCTIONS) {
185047e946e7SWyllys Ingersoll 			/* if we're already logged in, just verify the hash */
185147e946e7SWyllys Ingersoll 			if (memcmp(current_user_pin_sha, oldpin_hash,
185247e946e7SWyllys Ingersoll 			    SHA1_DIGEST_LENGTH)) {
185347e946e7SWyllys Ingersoll 				return (CKR_PIN_INCORRECT);
185447e946e7SWyllys Ingersoll 			}
185547e946e7SWyllys Ingersoll 		} else {
185647e946e7SWyllys Ingersoll 			if ((rc = verify_user_pin(sess->hContext,
185747e946e7SWyllys Ingersoll 			    oldpin_hash))) {
185847e946e7SWyllys Ingersoll 				return (rc);
185947e946e7SWyllys Ingersoll 			}
186047e946e7SWyllys Ingersoll 		}
186147e946e7SWyllys Ingersoll 
186247e946e7SWyllys Ingersoll 		if ((rc = check_pin_properties(CKU_USER, newpin_hash,
186347e946e7SWyllys Ingersoll 		    ulNewPinLen)))
186447e946e7SWyllys Ingersoll 			return (rc);
186547e946e7SWyllys Ingersoll 
186647e946e7SWyllys Ingersoll 		/* change the auth on the TSS object */
186747e946e7SWyllys Ingersoll 		if (tss_change_auth(sess->hContext,
186847e946e7SWyllys Ingersoll 		    hPrivateLeafKey, hPrivateRootKey,
186947e946e7SWyllys Ingersoll 		    privateLeafKeyUUID, privateRootKeyUUID,
187047e946e7SWyllys Ingersoll 		    newpin_hash))
187147e946e7SWyllys Ingersoll 			return (CKR_FUNCTION_FAILED);
187247e946e7SWyllys Ingersoll 
187347e946e7SWyllys Ingersoll 	} else if (sess->session_info.state == CKS_RW_SO_FUNCTIONS) {
187447e946e7SWyllys Ingersoll 		if (not_initialized) {
187547e946e7SWyllys Ingersoll 			if (memcmp(default_so_pin_sha, oldpin_hash,
187647e946e7SWyllys Ingersoll 			    SHA1_DIGEST_LENGTH))
187747e946e7SWyllys Ingersoll 				return (CKR_PIN_INCORRECT);
187847e946e7SWyllys Ingersoll 
187947e946e7SWyllys Ingersoll 			if ((rc = check_pin_properties(CKU_SO,
188047e946e7SWyllys Ingersoll 			    newpin_hash, ulNewPinLen)))
188147e946e7SWyllys Ingersoll 				return (rc);
188247e946e7SWyllys Ingersoll 
188347e946e7SWyllys Ingersoll 			if ((rc = token_create_public_tree(sess->hContext,
188447e946e7SWyllys Ingersoll 			    newpin_hash)))
188547e946e7SWyllys Ingersoll 				return (CKR_FUNCTION_FAILED);
188647e946e7SWyllys Ingersoll 
188747e946e7SWyllys Ingersoll 			nv_token_data->token_info.flags &=
188847e946e7SWyllys Ingersoll 			    ~(CKF_SO_PIN_TO_BE_CHANGED);
188947e946e7SWyllys Ingersoll 
189047e946e7SWyllys Ingersoll 			return (save_token_data(nv_token_data));
189147e946e7SWyllys Ingersoll 		}
189247e946e7SWyllys Ingersoll 
189347e946e7SWyllys Ingersoll 		if (memcmp(current_so_pin_sha, oldpin_hash,
189447e946e7SWyllys Ingersoll 		    SHA1_DIGEST_LENGTH))
189547e946e7SWyllys Ingersoll 			return (CKR_PIN_INCORRECT);
189647e946e7SWyllys Ingersoll 
189747e946e7SWyllys Ingersoll 		if ((rc = check_pin_properties(CKU_SO, newpin_hash,
189847e946e7SWyllys Ingersoll 		    ulNewPinLen)))
189947e946e7SWyllys Ingersoll 			return (rc);
190047e946e7SWyllys Ingersoll 
190147e946e7SWyllys Ingersoll 		/* change auth on the SO's leaf key */
190247e946e7SWyllys Ingersoll 		if (tss_change_auth(sess->hContext,
190347e946e7SWyllys Ingersoll 		    hPublicLeafKey, hPublicRootKey,
190447e946e7SWyllys Ingersoll 		    publicLeafKeyUUID, publicRootKeyUUID,
190547e946e7SWyllys Ingersoll 		    newpin_hash))
190647e946e7SWyllys Ingersoll 			return (CKR_FUNCTION_FAILED);
190747e946e7SWyllys Ingersoll 
190847e946e7SWyllys Ingersoll 	} else {
190947e946e7SWyllys Ingersoll 		rc = CKR_SESSION_READ_ONLY;
191047e946e7SWyllys Ingersoll 	}
191147e946e7SWyllys Ingersoll 
191247e946e7SWyllys Ingersoll 	return (rc);
191347e946e7SWyllys Ingersoll }
191447e946e7SWyllys Ingersoll 
191547e946e7SWyllys Ingersoll /* only called at token init time */
191647e946e7SWyllys Ingersoll CK_RV
191747e946e7SWyllys Ingersoll token_specific_verify_so_pin(TSS_HCONTEXT hContext, CK_CHAR_PTR pPin,
191847e946e7SWyllys Ingersoll     CK_ULONG ulPinLen)
191947e946e7SWyllys Ingersoll {
192047e946e7SWyllys Ingersoll 	CK_BYTE hash_sha[SHA1_DIGEST_LENGTH];
192147e946e7SWyllys Ingersoll 	CK_RV rc;
192247e946e7SWyllys Ingersoll 	TSS_RESULT result;
192347e946e7SWyllys Ingersoll 	TSS_HKEY hSRK;
192447e946e7SWyllys Ingersoll 
192547e946e7SWyllys Ingersoll 	if ((rc = compute_sha(pPin, ulPinLen, hash_sha))) {
192647e946e7SWyllys Ingersoll 		return (CKR_FUNCTION_FAILED);
192747e946e7SWyllys Ingersoll 	}
192847e946e7SWyllys Ingersoll 	if ((rc = token_load_srk(hContext, &hSRK))) {
192947e946e7SWyllys Ingersoll 		return (CKR_FUNCTION_FAILED);
193047e946e7SWyllys Ingersoll 	}
193147e946e7SWyllys Ingersoll 
193247e946e7SWyllys Ingersoll 	/*
193347e946e7SWyllys Ingersoll 	 * TRYME INSTEAD:
193447e946e7SWyllys Ingersoll 	 * - find publicRootKeyUUID
193547e946e7SWyllys Ingersoll 	 * - Load publicRootKey by UUID (SRK parent)
193647e946e7SWyllys Ingersoll 	 * - find publicLeafKeyUUID
193747e946e7SWyllys Ingersoll 	 * - Load publicLeafKey by UUID (publicRootKey parent)
193847e946e7SWyllys Ingersoll 	 * - set password policy on publicLeafKey
193947e946e7SWyllys Ingersoll 	 */
194047e946e7SWyllys Ingersoll 	if (local_uuid_is_null(&publicRootKeyUUID) &&
194147e946e7SWyllys Ingersoll 	    find_uuid(TPMTOK_PUBLIC_ROOT_KEY_ID, &publicRootKeyUUID)) {
194247e946e7SWyllys Ingersoll 		/*
194347e946e7SWyllys Ingersoll 		 * The SO hasn't set her PIN yet, compare the
194447e946e7SWyllys Ingersoll 		 * login pin with the hard-coded value.
194547e946e7SWyllys Ingersoll 		 */
194647e946e7SWyllys Ingersoll 		if (memcmp(default_so_pin_sha, hash_sha,
194747e946e7SWyllys Ingersoll 		    SHA1_DIGEST_LENGTH)) {
194847e946e7SWyllys Ingersoll 			return (CKR_PIN_INCORRECT);
194947e946e7SWyllys Ingersoll 		}
195047e946e7SWyllys Ingersoll 		return (CKR_OK);
195147e946e7SWyllys Ingersoll 	}
195247e946e7SWyllys Ingersoll 
195347e946e7SWyllys Ingersoll 	result = Tspi_Context_GetKeyByUUID(hContext,
195447e946e7SWyllys Ingersoll 	    TSS_PS_TYPE_USER, publicRootKeyUUID, &hPublicRootKey);
195547e946e7SWyllys Ingersoll 
195647e946e7SWyllys Ingersoll 	if (result)
195747e946e7SWyllys Ingersoll 		return (CKR_FUNCTION_FAILED);
195847e946e7SWyllys Ingersoll 
195947e946e7SWyllys Ingersoll 	result = Tspi_Key_LoadKey(hPublicRootKey, hSRK);
196047e946e7SWyllys Ingersoll 	if (result)
196147e946e7SWyllys Ingersoll 		return (CKR_FUNCTION_FAILED);
196247e946e7SWyllys Ingersoll 
196347e946e7SWyllys Ingersoll 	if (local_uuid_is_null(&publicLeafKeyUUID) &&
196447e946e7SWyllys Ingersoll 	    find_uuid(TPMTOK_PUBLIC_LEAF_KEY_ID, &publicLeafKeyUUID))
196547e946e7SWyllys Ingersoll 		return (CKR_FUNCTION_FAILED);
196647e946e7SWyllys Ingersoll 
196747e946e7SWyllys Ingersoll 	result = Tspi_Context_GetKeyByUUID(hContext,
196847e946e7SWyllys Ingersoll 	    TSS_PS_TYPE_USER, publicLeafKeyUUID, &hPublicLeafKey);
196947e946e7SWyllys Ingersoll 	if (result)
197047e946e7SWyllys Ingersoll 		return (CKR_FUNCTION_FAILED);
197147e946e7SWyllys Ingersoll 
1972ab8176c2SWyllys Ingersoll 	result = tss_assign_secret_key_policy(hContext, TSS_POLICY_USAGE,
1973ab8176c2SWyllys Ingersoll 	    hPublicLeafKey, hash_sha);
197447e946e7SWyllys Ingersoll 	if (result)
197547e946e7SWyllys Ingersoll 		return (CKR_FUNCTION_FAILED);
197647e946e7SWyllys Ingersoll 
197747e946e7SWyllys Ingersoll 	result = Tspi_Key_LoadKey(hPublicLeafKey, hPublicRootKey);
197847e946e7SWyllys Ingersoll 	if (result)
197947e946e7SWyllys Ingersoll 		return (CKR_FUNCTION_FAILED);
198047e946e7SWyllys Ingersoll 
198147e946e7SWyllys Ingersoll 	/* If the hash given is wrong, the verify will fail */
198247e946e7SWyllys Ingersoll 	if ((rc = token_verify_pin(hContext, hPublicLeafKey))) {
198347e946e7SWyllys Ingersoll 		return (rc);
198447e946e7SWyllys Ingersoll 	}
198547e946e7SWyllys Ingersoll 
198647e946e7SWyllys Ingersoll 	return (CKR_OK);
198747e946e7SWyllys Ingersoll }
198847e946e7SWyllys Ingersoll 
198947e946e7SWyllys Ingersoll CK_RV
1990ab8176c2SWyllys Ingersoll token_specific_final(TSS_HCONTEXT hContext)
199147e946e7SWyllys Ingersoll {
1992ab8176c2SWyllys Ingersoll 	if (hPublicRootKey != NULL_HKEY) {
1993ab8176c2SWyllys Ingersoll 		Tspi_Context_CloseObject(hContext, hPublicRootKey);
1994ab8176c2SWyllys Ingersoll 		hPublicRootKey = NULL_HKEY;
1995ab8176c2SWyllys Ingersoll 	}
1996ab8176c2SWyllys Ingersoll 	if (hPublicLeafKey != NULL_HKEY) {
1997ab8176c2SWyllys Ingersoll 		Tspi_Context_CloseObject(hContext, hPublicLeafKey);
1998ab8176c2SWyllys Ingersoll 		hPublicLeafKey = NULL_HKEY;
1999ab8176c2SWyllys Ingersoll 	}
2000ab8176c2SWyllys Ingersoll 	if (hPrivateRootKey != NULL_HKEY) {
2001ab8176c2SWyllys Ingersoll 		Tspi_Context_CloseObject(hContext, hPrivateRootKey);
2002ab8176c2SWyllys Ingersoll 		hPrivateRootKey = NULL_HKEY;
2003ab8176c2SWyllys Ingersoll 	}
2004ab8176c2SWyllys Ingersoll 	if (hPrivateLeafKey != NULL_HKEY) {
2005ab8176c2SWyllys Ingersoll 		Tspi_Context_CloseObject(hContext, hPrivateLeafKey);
2006ab8176c2SWyllys Ingersoll 		hPrivateLeafKey = NULL_HKEY;
2007ab8176c2SWyllys Ingersoll 	}
200847e946e7SWyllys Ingersoll 	return (CKR_OK);
200947e946e7SWyllys Ingersoll }
201047e946e7SWyllys Ingersoll 
201147e946e7SWyllys Ingersoll /*
201247e946e7SWyllys Ingersoll  * Wrap the 20 bytes of auth data and store in an attribute of the two
201347e946e7SWyllys Ingersoll  * keys.
201447e946e7SWyllys Ingersoll  */
201547e946e7SWyllys Ingersoll static CK_RV
201647e946e7SWyllys Ingersoll token_wrap_auth_data(TSS_HCONTEXT hContext,
201747e946e7SWyllys Ingersoll 	CK_BYTE *authData, TEMPLATE *publ_tmpl,
201847e946e7SWyllys Ingersoll 	TEMPLATE *priv_tmpl)
201947e946e7SWyllys Ingersoll {
202047e946e7SWyllys Ingersoll 	CK_RV		rc;
202147e946e7SWyllys Ingersoll 	CK_ATTRIBUTE	*new_attr;
202247e946e7SWyllys Ingersoll 
202347e946e7SWyllys Ingersoll 	TSS_RESULT	ret;
202447e946e7SWyllys Ingersoll 	TSS_HKEY	hParentKey;
202547e946e7SWyllys Ingersoll 	TSS_HENCDATA	hEncData;
202647e946e7SWyllys Ingersoll 	BYTE		*blob;
202747e946e7SWyllys Ingersoll 	UINT32		blob_size;
202847e946e7SWyllys Ingersoll 
202947e946e7SWyllys Ingersoll 	if ((hPrivateLeafKey == NULL_HKEY) && (hPublicLeafKey == NULL_HKEY)) {
203047e946e7SWyllys Ingersoll 		return (CKR_FUNCTION_FAILED);
203147e946e7SWyllys Ingersoll 	} else if (hPublicLeafKey != NULL_HKEY) {
203247e946e7SWyllys Ingersoll 		hParentKey = hPublicLeafKey;
203347e946e7SWyllys Ingersoll 	} else {
203447e946e7SWyllys Ingersoll 		hParentKey = hPrivateLeafKey;
203547e946e7SWyllys Ingersoll 	}
203647e946e7SWyllys Ingersoll 
203747e946e7SWyllys Ingersoll 	/* create the encrypted data object */
203847e946e7SWyllys Ingersoll 	if ((ret = Tspi_Context_CreateObject(hContext,
203947e946e7SWyllys Ingersoll 	    TSS_OBJECT_TYPE_ENCDATA, TSS_ENCDATA_BIND, &hEncData))) {
204047e946e7SWyllys Ingersoll 		stlogit("Tspi_Context_CreateObject: 0x%0x - %s",
204147e946e7SWyllys Ingersoll 		    ret, Trspi_Error_String(ret));
204247e946e7SWyllys Ingersoll 		return (CKR_FUNCTION_FAILED);
204347e946e7SWyllys Ingersoll 	}
204447e946e7SWyllys Ingersoll 
204547e946e7SWyllys Ingersoll 	if ((ret = Tspi_Data_Bind(hEncData, hParentKey, SHA1_DIGEST_LENGTH,
204647e946e7SWyllys Ingersoll 	    authData))) {
204747e946e7SWyllys Ingersoll 		stlogit("Tspi_Data_Bind: 0x%0x - %s",
204847e946e7SWyllys Ingersoll 		    ret, Trspi_Error_String(ret));
204947e946e7SWyllys Ingersoll 		return (CKR_FUNCTION_FAILED);
205047e946e7SWyllys Ingersoll 	}
205147e946e7SWyllys Ingersoll 
205247e946e7SWyllys Ingersoll 	/* pull the encrypted data out of the encrypted data object */
205347e946e7SWyllys Ingersoll 	if ((ret = Tspi_GetAttribData(hEncData, TSS_TSPATTRIB_ENCDATA_BLOB,
205447e946e7SWyllys Ingersoll 	    TSS_TSPATTRIB_ENCDATABLOB_BLOB, &blob_size, &blob))) {
205547e946e7SWyllys Ingersoll 		stlogit("Tspi_SetAttribData: 0x%0x - %s",
205647e946e7SWyllys Ingersoll 		    ret, Trspi_Error_String(ret));
205747e946e7SWyllys Ingersoll 		return (CKR_FUNCTION_FAILED);
205847e946e7SWyllys Ingersoll 	}
205947e946e7SWyllys Ingersoll 
206047e946e7SWyllys Ingersoll 	if ((rc = build_attribute(CKA_ENC_AUTHDATA, blob, blob_size,
206147e946e7SWyllys Ingersoll 	    &new_attr))) {
206247e946e7SWyllys Ingersoll 		return (rc);
206347e946e7SWyllys Ingersoll 	}
206447e946e7SWyllys Ingersoll 	(void) template_update_attribute(publ_tmpl, new_attr);
206547e946e7SWyllys Ingersoll 
206647e946e7SWyllys Ingersoll 	if ((rc = build_attribute(CKA_ENC_AUTHDATA, blob,
206747e946e7SWyllys Ingersoll 	    blob_size, &new_attr))) {
206847e946e7SWyllys Ingersoll 		return (rc);
206947e946e7SWyllys Ingersoll 	}
207047e946e7SWyllys Ingersoll 	(void) template_update_attribute(priv_tmpl, new_attr);
207147e946e7SWyllys Ingersoll 
207247e946e7SWyllys Ingersoll 	return (rc);
207347e946e7SWyllys Ingersoll }
207447e946e7SWyllys Ingersoll 
207547e946e7SWyllys Ingersoll static CK_RV
207647e946e7SWyllys Ingersoll token_unwrap_auth_data(TSS_HCONTEXT hContext, CK_BYTE *encAuthData,
207747e946e7SWyllys Ingersoll 	CK_ULONG encAuthDataLen, TSS_HKEY hKey,
207847e946e7SWyllys Ingersoll 	BYTE **authData)
207947e946e7SWyllys Ingersoll {
208047e946e7SWyllys Ingersoll 	TSS_RESULT	result;
208147e946e7SWyllys Ingersoll 	TSS_HENCDATA	hEncData;
208247e946e7SWyllys Ingersoll 	BYTE		*buf;
208347e946e7SWyllys Ingersoll 	UINT32		buf_size;
208447e946e7SWyllys Ingersoll 
208547e946e7SWyllys Ingersoll 	if ((result = Tspi_Context_CreateObject(hContext,
208647e946e7SWyllys Ingersoll 	    TSS_OBJECT_TYPE_ENCDATA, TSS_ENCDATA_BIND, &hEncData))) {
208747e946e7SWyllys Ingersoll 		stlogit("Tspi_Context_CreateObject: 0x%0x - %s",
208847e946e7SWyllys Ingersoll 		    result, Trspi_Error_String(result));
208947e946e7SWyllys Ingersoll 		return (CKR_FUNCTION_FAILED);
209047e946e7SWyllys Ingersoll 	}
209147e946e7SWyllys Ingersoll 
209247e946e7SWyllys Ingersoll 	if ((result = Tspi_SetAttribData(hEncData,
209347e946e7SWyllys Ingersoll 	    TSS_TSPATTRIB_ENCDATA_BLOB, TSS_TSPATTRIB_ENCDATABLOB_BLOB,
209447e946e7SWyllys Ingersoll 	    encAuthDataLen, encAuthData))) {
209547e946e7SWyllys Ingersoll 		stlogit("Tspi_SetAttribData: 0x%0x - %s",
209647e946e7SWyllys Ingersoll 		    result, Trspi_Error_String(result));
209747e946e7SWyllys Ingersoll 		return (CKR_FUNCTION_FAILED);
209847e946e7SWyllys Ingersoll 	}
209947e946e7SWyllys Ingersoll 
210047e946e7SWyllys Ingersoll 	/* unbind the data, receiving the plaintext back */
210147e946e7SWyllys Ingersoll 	if ((result = Tspi_Data_Unbind(hEncData, hKey, &buf_size, &buf))) {
210247e946e7SWyllys Ingersoll 		stlogit("Tspi_Data_Unbind: 0x%0x - %s",
210347e946e7SWyllys Ingersoll 		    result, Trspi_Error_String(result));
210447e946e7SWyllys Ingersoll 		return (CKR_FUNCTION_FAILED);
210547e946e7SWyllys Ingersoll 	}
210647e946e7SWyllys Ingersoll 
210747e946e7SWyllys Ingersoll 	if (buf_size != SHA1_DIGEST_LENGTH) {
210847e946e7SWyllys Ingersoll 		return (CKR_FUNCTION_FAILED);
210947e946e7SWyllys Ingersoll 	}
211047e946e7SWyllys Ingersoll 
211147e946e7SWyllys Ingersoll 	*authData = buf;
211247e946e7SWyllys Ingersoll 
211347e946e7SWyllys Ingersoll 	return (CKR_OK);
211447e946e7SWyllys Ingersoll }
211547e946e7SWyllys Ingersoll 
211647e946e7SWyllys Ingersoll CK_RV
211747e946e7SWyllys Ingersoll token_specific_rsa_generate_keypair(
211847e946e7SWyllys Ingersoll 	TSS_HCONTEXT hContext,
211947e946e7SWyllys Ingersoll 	TEMPLATE  *publ_tmpl,
212047e946e7SWyllys Ingersoll 	TEMPLATE  *priv_tmpl)
212147e946e7SWyllys Ingersoll {
212247e946e7SWyllys Ingersoll 	CK_ATTRIBUTE	*attr = NULL;
212347e946e7SWyllys Ingersoll 	CK_ULONG	mod_bits = 0;
212447e946e7SWyllys Ingersoll 	CK_BBOOL	flag;
212547e946e7SWyllys Ingersoll 	CK_RV		rc;
212647e946e7SWyllys Ingersoll 
212747e946e7SWyllys Ingersoll 	TSS_FLAG	initFlags = 0;
212847e946e7SWyllys Ingersoll 	BYTE		authHash[SHA1_DIGEST_LENGTH];
212947e946e7SWyllys Ingersoll 	BYTE		*authData = NULL;
213047e946e7SWyllys Ingersoll 	TSS_HKEY	hKey = NULL_HKEY;
213147e946e7SWyllys Ingersoll 	TSS_HKEY	hParentKey = NULL_HKEY;
213247e946e7SWyllys Ingersoll 	TSS_RESULT	result;
213347e946e7SWyllys Ingersoll 	UINT32		ulBlobLen;
213447e946e7SWyllys Ingersoll 	BYTE		*rgbBlob;
213547e946e7SWyllys Ingersoll 
213647e946e7SWyllys Ingersoll 	/* Make sure the public exponent is usable */
213747e946e7SWyllys Ingersoll 	if ((util_check_public_exponent(publ_tmpl))) {
213847e946e7SWyllys Ingersoll 		return (CKR_TEMPLATE_INCONSISTENT);
213947e946e7SWyllys Ingersoll 	}
214047e946e7SWyllys Ingersoll 
214147e946e7SWyllys Ingersoll 	flag = template_attribute_find(publ_tmpl, CKA_MODULUS_BITS, &attr);
214247e946e7SWyllys Ingersoll 	if (!flag) {
214347e946e7SWyllys Ingersoll 		return (CKR_TEMPLATE_INCOMPLETE);
214447e946e7SWyllys Ingersoll 	}
214547e946e7SWyllys Ingersoll 	mod_bits = *(CK_ULONG *)attr->pValue;
214647e946e7SWyllys Ingersoll 
214747e946e7SWyllys Ingersoll 	if ((initFlags = util_get_keysize_flag(mod_bits)) == 0) {
214847e946e7SWyllys Ingersoll 		return (CKR_KEY_SIZE_RANGE);
214947e946e7SWyllys Ingersoll 	}
215047e946e7SWyllys Ingersoll 
215147e946e7SWyllys Ingersoll 	/*
215247e946e7SWyllys Ingersoll 	 * If we're not logged in, hPrivateLeafKey and hPublicLeafKey
215347e946e7SWyllys Ingersoll 	 * should be NULL.
215447e946e7SWyllys Ingersoll 	 */
215547e946e7SWyllys Ingersoll 	if ((hPrivateLeafKey == NULL_HKEY) &&
215647e946e7SWyllys Ingersoll 	    (hPublicLeafKey == NULL_HKEY)) {
215747e946e7SWyllys Ingersoll 		/* public session, wrap key with the PRK */
215847e946e7SWyllys Ingersoll 		initFlags |= TSS_KEY_TYPE_LEGACY |
215947e946e7SWyllys Ingersoll 		    TSS_KEY_NO_AUTHORIZATION | TSS_KEY_MIGRATABLE;
216047e946e7SWyllys Ingersoll 
216147e946e7SWyllys Ingersoll 		if ((result = token_load_public_root_key(hContext))) {
216247e946e7SWyllys Ingersoll 			return (CKR_FUNCTION_FAILED);
216347e946e7SWyllys Ingersoll 		}
216447e946e7SWyllys Ingersoll 
216547e946e7SWyllys Ingersoll 		hParentKey = hPublicRootKey;
216647e946e7SWyllys Ingersoll 	} else if (hPrivateLeafKey != NULL_HKEY) {
216747e946e7SWyllys Ingersoll 		/* logged in USER session */
216847e946e7SWyllys Ingersoll 		initFlags |= TSS_KEY_TYPE_LEGACY |
216947e946e7SWyllys Ingersoll 		    TSS_KEY_AUTHORIZATION | TSS_KEY_MIGRATABLE;
217047e946e7SWyllys Ingersoll 
217147e946e7SWyllys Ingersoll 		/* get a random SHA1 hash for the auth data */
217247e946e7SWyllys Ingersoll 		if ((rc = token_rng(hContext, authHash, SHA1_DIGEST_LENGTH))) {
217347e946e7SWyllys Ingersoll 			return (CKR_FUNCTION_FAILED);
217447e946e7SWyllys Ingersoll 		}
217547e946e7SWyllys Ingersoll 
217647e946e7SWyllys Ingersoll 		authData = authHash;
217747e946e7SWyllys Ingersoll 		hParentKey = hPrivateRootKey;
217847e946e7SWyllys Ingersoll 	} else {
217947e946e7SWyllys Ingersoll 		/* logged in SO session */
218047e946e7SWyllys Ingersoll 		initFlags |= TSS_KEY_TYPE_LEGACY |
218147e946e7SWyllys Ingersoll 		    TSS_KEY_AUTHORIZATION | TSS_KEY_MIGRATABLE;
218247e946e7SWyllys Ingersoll 
218347e946e7SWyllys Ingersoll 		/* get a random SHA1 hash for the auth data */
218447e946e7SWyllys Ingersoll 		if ((rc = token_rng(hContext, authHash, SHA1_DIGEST_LENGTH))) {
218547e946e7SWyllys Ingersoll 			return (CKR_FUNCTION_FAILED);
218647e946e7SWyllys Ingersoll 		}
218747e946e7SWyllys Ingersoll 
218847e946e7SWyllys Ingersoll 		authData = authHash;
218947e946e7SWyllys Ingersoll 		hParentKey = hPublicRootKey;
219047e946e7SWyllys Ingersoll 	}
219147e946e7SWyllys Ingersoll 
219247e946e7SWyllys Ingersoll 	if ((result = tss_generate_key(hContext, initFlags, authData,
219347e946e7SWyllys Ingersoll 	    hParentKey, &hKey))) {
219447e946e7SWyllys Ingersoll 		return (result);
219547e946e7SWyllys Ingersoll 	}
219647e946e7SWyllys Ingersoll 
219747e946e7SWyllys Ingersoll 	if ((result = Tspi_GetAttribData(hKey, TSS_TSPATTRIB_KEY_BLOB,
219847e946e7SWyllys Ingersoll 	    TSS_TSPATTRIB_KEYBLOB_BLOB, &ulBlobLen, &rgbBlob))) {
219947e946e7SWyllys Ingersoll 		stlogit("Tspi_GetAttribData: 0x%0x - %s",
220047e946e7SWyllys Ingersoll 		    result, Trspi_Error_String(result));
220147e946e7SWyllys Ingersoll 		return (CKR_FUNCTION_FAILED);
220247e946e7SWyllys Ingersoll 	}
220347e946e7SWyllys Ingersoll 
220447e946e7SWyllys Ingersoll 	if ((rc = build_attribute(CKA_IBM_OPAQUE, rgbBlob,
220547e946e7SWyllys Ingersoll 	    ulBlobLen, &attr))) {
220647e946e7SWyllys Ingersoll 		Tspi_Context_FreeMemory(hContext, rgbBlob);
220747e946e7SWyllys Ingersoll 		return (rc);
220847e946e7SWyllys Ingersoll 	}
220947e946e7SWyllys Ingersoll 	(void) template_update_attribute(priv_tmpl, attr);
221047e946e7SWyllys Ingersoll 	if ((rc = build_attribute(CKA_IBM_OPAQUE, rgbBlob,
221147e946e7SWyllys Ingersoll 	    ulBlobLen, &attr))) {
221247e946e7SWyllys Ingersoll 		Tspi_Context_FreeMemory(hContext, rgbBlob);
221347e946e7SWyllys Ingersoll 		return (rc);
221447e946e7SWyllys Ingersoll 	}
221547e946e7SWyllys Ingersoll 	(void) template_update_attribute(publ_tmpl, attr);
221647e946e7SWyllys Ingersoll 
221747e946e7SWyllys Ingersoll 	Tspi_Context_FreeMemory(hContext, rgbBlob);
221847e946e7SWyllys Ingersoll 
221947e946e7SWyllys Ingersoll 	/* grab the public key to put into the public key object */
222047e946e7SWyllys Ingersoll 	if ((result = Tspi_GetAttribData(hKey, TSS_TSPATTRIB_RSAKEY_INFO,
222147e946e7SWyllys Ingersoll 	    TSS_TSPATTRIB_KEYINFO_RSA_MODULUS, &ulBlobLen, &rgbBlob))) {
222247e946e7SWyllys Ingersoll 		stlogit("Tspi_GetAttribData: 0x%0x - %s",
222347e946e7SWyllys Ingersoll 		    result, Trspi_Error_String(result));
222447e946e7SWyllys Ingersoll 		return (result);
222547e946e7SWyllys Ingersoll 	}
222647e946e7SWyllys Ingersoll 
222747e946e7SWyllys Ingersoll 	/* add the public key blob to the object template */
222847e946e7SWyllys Ingersoll 	if ((rc = build_attribute(CKA_MODULUS, rgbBlob, ulBlobLen, &attr))) {
222947e946e7SWyllys Ingersoll 		Tspi_Context_FreeMemory(hContext, rgbBlob);
223047e946e7SWyllys Ingersoll 		return (rc);
223147e946e7SWyllys Ingersoll 	}
223247e946e7SWyllys Ingersoll 	(void) template_update_attribute(publ_tmpl, attr);
223347e946e7SWyllys Ingersoll 
223447e946e7SWyllys Ingersoll 	/* add the public key blob to the object template */
223547e946e7SWyllys Ingersoll 	if ((rc = build_attribute(CKA_MODULUS, rgbBlob, ulBlobLen, &attr))) {
223647e946e7SWyllys Ingersoll 		Tspi_Context_FreeMemory(hContext, rgbBlob);
223747e946e7SWyllys Ingersoll 		return (rc);
223847e946e7SWyllys Ingersoll 	}
223947e946e7SWyllys Ingersoll 	(void) template_update_attribute(priv_tmpl, attr);
224047e946e7SWyllys Ingersoll 	Tspi_Context_FreeMemory(hContext, rgbBlob);
224147e946e7SWyllys Ingersoll 
224247e946e7SWyllys Ingersoll 	/* wrap the authdata and put it into an object */
224347e946e7SWyllys Ingersoll 	if (authData != NULL) {
224447e946e7SWyllys Ingersoll 		rc = token_wrap_auth_data(hContext, authData, publ_tmpl,
224547e946e7SWyllys Ingersoll 		    priv_tmpl);
224647e946e7SWyllys Ingersoll 	}
224747e946e7SWyllys Ingersoll 
224847e946e7SWyllys Ingersoll 	return (rc);
224947e946e7SWyllys Ingersoll }
225047e946e7SWyllys Ingersoll 
225147e946e7SWyllys Ingersoll static CK_RV
225247e946e7SWyllys Ingersoll token_rsa_load_key(
225347e946e7SWyllys Ingersoll 	TSS_HCONTEXT hContext,
225447e946e7SWyllys Ingersoll 	OBJECT *key_obj,
225547e946e7SWyllys Ingersoll 	TSS_HKEY *phKey)
225647e946e7SWyllys Ingersoll {
225747e946e7SWyllys Ingersoll 	TSS_RESULT result;
225847e946e7SWyllys Ingersoll 	TSS_HPOLICY hPolicy = NULL_HPOLICY;
225947e946e7SWyllys Ingersoll 	TSS_HKEY	hParentKey;
226047e946e7SWyllys Ingersoll 	BYTE		*authData = NULL;
226147e946e7SWyllys Ingersoll 	CK_ATTRIBUTE	*attr;
226247e946e7SWyllys Ingersoll 	CK_RV		rc;
226347e946e7SWyllys Ingersoll 	CK_OBJECT_HANDLE handle;
2264ab8176c2SWyllys Ingersoll 	CK_ULONG	class;
226547e946e7SWyllys Ingersoll 
226647e946e7SWyllys Ingersoll 	if (hPrivateLeafKey != NULL_HKEY) {
226747e946e7SWyllys Ingersoll 		hParentKey = hPrivateRootKey;
226847e946e7SWyllys Ingersoll 	} else {
226947e946e7SWyllys Ingersoll 		if ((result = token_load_public_root_key(hContext)))
227047e946e7SWyllys Ingersoll 			return (CKR_FUNCTION_FAILED);
227147e946e7SWyllys Ingersoll 
227247e946e7SWyllys Ingersoll 		hParentKey = hPublicRootKey;
227347e946e7SWyllys Ingersoll 	}
227447e946e7SWyllys Ingersoll 
2275ab8176c2SWyllys Ingersoll 	*phKey = NULL;
2276ab8176c2SWyllys Ingersoll 	if (template_attribute_find(key_obj->template, CKA_CLASS,
2277ab8176c2SWyllys Ingersoll 	    &attr) == FALSE) {
2278ab8176c2SWyllys Ingersoll 		return (CKR_TEMPLATE_INCOMPLETE);
2279ab8176c2SWyllys Ingersoll 	}
2280ab8176c2SWyllys Ingersoll 	class = *((CK_ULONG *)attr->pValue);
2281ab8176c2SWyllys Ingersoll 
2282ab8176c2SWyllys Ingersoll 	rc = template_attribute_find(key_obj->template,
2283ab8176c2SWyllys Ingersoll 	    CKA_IBM_OPAQUE, &attr);
2284ab8176c2SWyllys Ingersoll 	/*
2285ab8176c2SWyllys Ingersoll 	 * A public key cannot use the OPAQUE data attribute so they
2286ab8176c2SWyllys Ingersoll 	 * must be created in software.  A private key may not yet
2287ab8176c2SWyllys Ingersoll 	 * have its "opaque" data defined and needs to be created
2288ab8176c2SWyllys Ingersoll 	 * and loaded so it can be used inside the TPM.
2289ab8176c2SWyllys Ingersoll 	 */
2290ab8176c2SWyllys Ingersoll 	if (class == CKO_PUBLIC_KEY || rc == FALSE) {
229147e946e7SWyllys Ingersoll 		rc = object_mgr_find_in_map2(hContext, key_obj, &handle);
229247e946e7SWyllys Ingersoll 		if (rc != CKR_OK)
229347e946e7SWyllys Ingersoll 			return (CKR_FUNCTION_FAILED);
229447e946e7SWyllys Ingersoll 
229547e946e7SWyllys Ingersoll 		if ((rc = token_load_key(hContext,
229647e946e7SWyllys Ingersoll 		    handle, hParentKey, NULL, phKey))) {
229747e946e7SWyllys Ingersoll 			return (rc);
229847e946e7SWyllys Ingersoll 		}
2299ab8176c2SWyllys Ingersoll 	}
2300ab8176c2SWyllys Ingersoll 	/*
2301ab8176c2SWyllys Ingersoll 	 * If this is a private key, get the blob and load it in the TPM.
2302ab8176c2SWyllys Ingersoll 	 * If it is public, the key is already loaded in software.
2303ab8176c2SWyllys Ingersoll 	 */
2304ab8176c2SWyllys Ingersoll 	if (class == CKO_PRIVATE_KEY) {
2305ab8176c2SWyllys Ingersoll 		/* If we already have a handle, just load it */
2306ab8176c2SWyllys Ingersoll 		if (*phKey != NULL) {
2307ab8176c2SWyllys Ingersoll 			result = Tspi_Key_LoadKey(*phKey, hParentKey);
2308ab8176c2SWyllys Ingersoll 			if (result) {
2309ab8176c2SWyllys Ingersoll 				stlogit("Tspi_Context_LoadKeyByBlob: "
2310ab8176c2SWyllys Ingersoll 				    "0x%0x - %s",
2311ab8176c2SWyllys Ingersoll 				    result, Trspi_Error_String(result));
2312ab8176c2SWyllys Ingersoll 				return (CKR_FUNCTION_FAILED);
2313ab8176c2SWyllys Ingersoll 			}
2314ab8176c2SWyllys Ingersoll 		} else {
231547e946e7SWyllys Ingersoll 			/* try again to get the CKA_IBM_OPAQUE attr */
231647e946e7SWyllys Ingersoll 			if ((rc = template_attribute_find(key_obj->template,
231747e946e7SWyllys Ingersoll 			    CKA_IBM_OPAQUE, &attr)) == FALSE) {
231847e946e7SWyllys Ingersoll 				return (rc);
231947e946e7SWyllys Ingersoll 			}
232047e946e7SWyllys Ingersoll 			if ((result = Tspi_Context_LoadKeyByBlob(hContext,
2321ab8176c2SWyllys Ingersoll 			    hParentKey, attr->ulValueLen, attr->pValue,
2322ab8176c2SWyllys Ingersoll 			    phKey))) {
2323ab8176c2SWyllys Ingersoll 				stlogit("Tspi_Context_LoadKeyByBlob: "
2324ab8176c2SWyllys Ingersoll 				    "0x%0x - %s",
232547e946e7SWyllys Ingersoll 				    result, Trspi_Error_String(result));
232647e946e7SWyllys Ingersoll 				return (CKR_FUNCTION_FAILED);
232747e946e7SWyllys Ingersoll 			}
2328ab8176c2SWyllys Ingersoll 		}
2329ab8176c2SWyllys Ingersoll 	}
233047e946e7SWyllys Ingersoll 
233147e946e7SWyllys Ingersoll 	/* auth data may be required */
233247e946e7SWyllys Ingersoll 	if (template_attribute_find(key_obj->template, CKA_ENC_AUTHDATA,
233347e946e7SWyllys Ingersoll 	    &attr) == TRUE && attr) {
233447e946e7SWyllys Ingersoll 		if ((hPrivateLeafKey == NULL_HKEY) &&
233547e946e7SWyllys Ingersoll 		    (hPublicLeafKey == NULL_HKEY)) {
233647e946e7SWyllys Ingersoll 			return (CKR_FUNCTION_FAILED);
233747e946e7SWyllys Ingersoll 		} else if (hPublicLeafKey != NULL_HKEY) {
233847e946e7SWyllys Ingersoll 			hParentKey = hPublicLeafKey;
233947e946e7SWyllys Ingersoll 		} else {
234047e946e7SWyllys Ingersoll 			hParentKey = hPrivateLeafKey;
234147e946e7SWyllys Ingersoll 		}
234247e946e7SWyllys Ingersoll 
234347e946e7SWyllys Ingersoll 		if ((result = token_unwrap_auth_data(hContext,
2344ab8176c2SWyllys Ingersoll 		    attr->pValue, attr->ulValueLen,
2345ab8176c2SWyllys Ingersoll 		    hParentKey, &authData))) {
234647e946e7SWyllys Ingersoll 			return (CKR_FUNCTION_FAILED);
234747e946e7SWyllys Ingersoll 		}
234847e946e7SWyllys Ingersoll 
234947e946e7SWyllys Ingersoll 		if ((result = Tspi_GetPolicyObject(*phKey,
235047e946e7SWyllys Ingersoll 		    TSS_POLICY_USAGE, &hPolicy))) {
235147e946e7SWyllys Ingersoll 			stlogit("Tspi_GetPolicyObject: 0x%0x - %s",
235247e946e7SWyllys Ingersoll 			    result, Trspi_Error_String(result));
235347e946e7SWyllys Ingersoll 			return (CKR_FUNCTION_FAILED);
235447e946e7SWyllys Ingersoll 		}
235547e946e7SWyllys Ingersoll 
235647e946e7SWyllys Ingersoll 		/*
235747e946e7SWyllys Ingersoll 		 * If the policy handle returned is the same as the
235847e946e7SWyllys Ingersoll 		 * context's default policy, then a new policy must
235947e946e7SWyllys Ingersoll 		 * be created and assigned to the key. Otherwise, just set the
236047e946e7SWyllys Ingersoll 		 * secret in the policy.
236147e946e7SWyllys Ingersoll 		 */
236247e946e7SWyllys Ingersoll 		if (hPolicy == hDefaultPolicy) {
236347e946e7SWyllys Ingersoll 			if ((result = Tspi_Context_CreateObject(hContext,
236447e946e7SWyllys Ingersoll 			    TSS_OBJECT_TYPE_POLICY, TSS_POLICY_USAGE,
236547e946e7SWyllys Ingersoll 			    &hPolicy))) {
236647e946e7SWyllys Ingersoll 				stlogit("Tspi_Context_CreateObject: "
236747e946e7SWyllys Ingersoll 				    "0x%0x - %s",
236847e946e7SWyllys Ingersoll 				    result, Trspi_Error_String(result));
236947e946e7SWyllys Ingersoll 				return (CKR_FUNCTION_FAILED);
237047e946e7SWyllys Ingersoll 			}
237147e946e7SWyllys Ingersoll 
237247e946e7SWyllys Ingersoll 			if ((result = Tspi_Policy_SetSecret(hPolicy,
237347e946e7SWyllys Ingersoll 			    TSS_SECRET_MODE_SHA1,
237447e946e7SWyllys Ingersoll 			    SHA1_DIGEST_LENGTH, authData))) {
237547e946e7SWyllys Ingersoll 				stlogit("Tspi_Policy_SetSecret: "
237647e946e7SWyllys Ingersoll 				    "0x%0x - %s",
237747e946e7SWyllys Ingersoll 				    result, Trspi_Error_String(result));
237847e946e7SWyllys Ingersoll 				return (CKR_FUNCTION_FAILED);
237947e946e7SWyllys Ingersoll 			}
238047e946e7SWyllys Ingersoll 
238147e946e7SWyllys Ingersoll 			if ((result = Tspi_Policy_AssignToObject(hPolicy,
238247e946e7SWyllys Ingersoll 			    *phKey))) {
238347e946e7SWyllys Ingersoll 				stlogit("Tspi_Policy_AssignToObject: "
238447e946e7SWyllys Ingersoll 				    "0x%0x - %s",
238547e946e7SWyllys Ingersoll 				    result, Trspi_Error_String(result));
238647e946e7SWyllys Ingersoll 				return (CKR_FUNCTION_FAILED);
238747e946e7SWyllys Ingersoll 			}
238847e946e7SWyllys Ingersoll 		} else if ((result = Tspi_Policy_SetSecret(hPolicy,
238947e946e7SWyllys Ingersoll 		    TSS_SECRET_MODE_SHA1, SHA1_DIGEST_LENGTH, authData))) {
239047e946e7SWyllys Ingersoll 			stlogit("Tspi_Policy_SetSecret: 0x%0x - %s",
239147e946e7SWyllys Ingersoll 			    result, Trspi_Error_String(result));
239247e946e7SWyllys Ingersoll 			return (CKR_FUNCTION_FAILED);
239347e946e7SWyllys Ingersoll 		}
239447e946e7SWyllys Ingersoll 
239547e946e7SWyllys Ingersoll 		Tspi_Context_FreeMemory(hContext, authData);
239647e946e7SWyllys Ingersoll 	}
239747e946e7SWyllys Ingersoll 
239847e946e7SWyllys Ingersoll 	return (CKR_OK);
239947e946e7SWyllys Ingersoll }
240047e946e7SWyllys Ingersoll 
240147e946e7SWyllys Ingersoll CK_RV
240247e946e7SWyllys Ingersoll tpm_decrypt_data(
240347e946e7SWyllys Ingersoll 	TSS_HCONTEXT hContext,
240447e946e7SWyllys Ingersoll 	TSS_HKEY    hKey,
240547e946e7SWyllys Ingersoll 	CK_BYTE   * in_data,
240647e946e7SWyllys Ingersoll 	CK_ULONG    in_data_len,
240747e946e7SWyllys Ingersoll 	CK_BYTE   * out_data,
240847e946e7SWyllys Ingersoll 	CK_ULONG  * out_data_len)
240947e946e7SWyllys Ingersoll {
241047e946e7SWyllys Ingersoll 	TSS_RESULT result;
241147e946e7SWyllys Ingersoll 	TSS_HENCDATA	hEncData = NULL_HENCDATA;
241247e946e7SWyllys Ingersoll 	UINT32		buf_size = 0, modLen;
241347e946e7SWyllys Ingersoll 	BYTE		*buf = NULL, *modulus = NULL;
241447e946e7SWyllys Ingersoll 	CK_ULONG	chunklen, remain, outlen;
241547e946e7SWyllys Ingersoll 
241647e946e7SWyllys Ingersoll 	/* push the data into the encrypted data object */
241747e946e7SWyllys Ingersoll 	if ((result = Tspi_Context_CreateObject(hContext,
241847e946e7SWyllys Ingersoll 	    TSS_OBJECT_TYPE_ENCDATA, TSS_ENCDATA_BIND, &hEncData))) {
241947e946e7SWyllys Ingersoll 		stlogit("Tspi_Context_CreateObject: 0x%0x - %s",
242047e946e7SWyllys Ingersoll 		    result, Trspi_Error_String(result));
242147e946e7SWyllys Ingersoll 		return (CKR_FUNCTION_FAILED);
242247e946e7SWyllys Ingersoll 	}
242347e946e7SWyllys Ingersoll 
242447e946e7SWyllys Ingersoll 	/*
242547e946e7SWyllys Ingersoll 	 * Figure out the modulus size so we can break the data
242647e946e7SWyllys Ingersoll 	 * into smaller chunks if necessary.
242747e946e7SWyllys Ingersoll 	 */
242847e946e7SWyllys Ingersoll 	if ((result = Tspi_GetAttribData(hKey, TSS_TSPATTRIB_RSAKEY_INFO,
242947e946e7SWyllys Ingersoll 	    TSS_TSPATTRIB_KEYINFO_RSA_MODULUS, &modLen, &modulus))) {
243047e946e7SWyllys Ingersoll 		stlogit("Tspi_GetAttribData: 0x%0x - %s",
243147e946e7SWyllys Ingersoll 		    result, Trspi_Error_String(result));
243247e946e7SWyllys Ingersoll 		return (result);
243347e946e7SWyllys Ingersoll 	}
243447e946e7SWyllys Ingersoll 	/* we don't need the actual modulus */
243547e946e7SWyllys Ingersoll 	Tspi_Context_FreeMemory(hContext, modulus);
243647e946e7SWyllys Ingersoll 
243747e946e7SWyllys Ingersoll 	chunklen = (in_data_len > modLen ? modLen : in_data_len);
243847e946e7SWyllys Ingersoll 	remain = in_data_len;
243947e946e7SWyllys Ingersoll 	outlen = 0;
244047e946e7SWyllys Ingersoll 
244147e946e7SWyllys Ingersoll 	while (remain > 0) {
244247e946e7SWyllys Ingersoll 		if ((result = Tspi_SetAttribData(hEncData,
244347e946e7SWyllys Ingersoll 		    TSS_TSPATTRIB_ENCDATA_BLOB,
244447e946e7SWyllys Ingersoll 		    TSS_TSPATTRIB_ENCDATABLOB_BLOB,
244547e946e7SWyllys Ingersoll 		    chunklen, in_data))) {
244647e946e7SWyllys Ingersoll 			stlogit("Tspi_SetAttribData: 0x%0x - %s",
244747e946e7SWyllys Ingersoll 			    result, Trspi_Error_String(result));
244847e946e7SWyllys Ingersoll 			return (CKR_FUNCTION_FAILED);
244947e946e7SWyllys Ingersoll 		}
245047e946e7SWyllys Ingersoll 
245147e946e7SWyllys Ingersoll 		/* unbind the data, receiving the plaintext back */
245247e946e7SWyllys Ingersoll 		if ((result = Tspi_Data_Unbind(hEncData, hKey,
245347e946e7SWyllys Ingersoll 		    &buf_size, &buf))) {
245447e946e7SWyllys Ingersoll 			stlogit("Tspi_Data_Unbind: 0x%0x - %s",
245547e946e7SWyllys Ingersoll 			    result, Trspi_Error_String(result));
245647e946e7SWyllys Ingersoll 			return (CKR_FUNCTION_FAILED);
245747e946e7SWyllys Ingersoll 		}
245847e946e7SWyllys Ingersoll 
245947e946e7SWyllys Ingersoll 		if (*out_data_len < buf_size + outlen) {
246047e946e7SWyllys Ingersoll 			Tspi_Context_FreeMemory(hContext, buf);
246147e946e7SWyllys Ingersoll 			return (CKR_BUFFER_TOO_SMALL);
246247e946e7SWyllys Ingersoll 		}
246347e946e7SWyllys Ingersoll 
246447e946e7SWyllys Ingersoll 		(void) memcpy(out_data + outlen, buf, buf_size);
246547e946e7SWyllys Ingersoll 
246647e946e7SWyllys Ingersoll 		outlen += buf_size;
246747e946e7SWyllys Ingersoll 		in_data += chunklen;
246847e946e7SWyllys Ingersoll 		remain -= chunklen;
246947e946e7SWyllys Ingersoll 
247047e946e7SWyllys Ingersoll 		Tspi_Context_FreeMemory(hContext, buf);
247147e946e7SWyllys Ingersoll 		if (chunklen > remain)
247247e946e7SWyllys Ingersoll 			chunklen = remain;
247347e946e7SWyllys Ingersoll 	}
247447e946e7SWyllys Ingersoll 	*out_data_len = outlen;
247547e946e7SWyllys Ingersoll 	return (CKR_OK);
247647e946e7SWyllys Ingersoll }
247747e946e7SWyllys Ingersoll 
247847e946e7SWyllys Ingersoll CK_RV
247947e946e7SWyllys Ingersoll token_specific_rsa_decrypt(
248047e946e7SWyllys Ingersoll 	TSS_HCONTEXT hContext,
248147e946e7SWyllys Ingersoll 	CK_BYTE   * in_data,
248247e946e7SWyllys Ingersoll 	CK_ULONG    in_data_len,
248347e946e7SWyllys Ingersoll 	CK_BYTE   * out_data,
248447e946e7SWyllys Ingersoll 	CK_ULONG  * out_data_len,
248547e946e7SWyllys Ingersoll 	OBJECT	  * key_obj)
248647e946e7SWyllys Ingersoll {
248747e946e7SWyllys Ingersoll 	CK_RV		rc;
248847e946e7SWyllys Ingersoll 	TSS_HKEY	hKey;
248947e946e7SWyllys Ingersoll 
249047e946e7SWyllys Ingersoll 	if ((rc = token_rsa_load_key(hContext, key_obj, &hKey))) {
249147e946e7SWyllys Ingersoll 		return (rc);
249247e946e7SWyllys Ingersoll 	}
249347e946e7SWyllys Ingersoll 
249447e946e7SWyllys Ingersoll 	rc = tpm_decrypt_data(hContext, hKey, in_data, in_data_len,
249547e946e7SWyllys Ingersoll 	    out_data, out_data_len);
249647e946e7SWyllys Ingersoll 
249747e946e7SWyllys Ingersoll 	return (rc);
249847e946e7SWyllys Ingersoll }
249947e946e7SWyllys Ingersoll 
250047e946e7SWyllys Ingersoll CK_RV
250147e946e7SWyllys Ingersoll token_specific_rsa_verify(
250247e946e7SWyllys Ingersoll 	TSS_HCONTEXT hContext,
250347e946e7SWyllys Ingersoll 	CK_BYTE   * in_data,
250447e946e7SWyllys Ingersoll 	CK_ULONG    in_data_len,
250547e946e7SWyllys Ingersoll 	CK_BYTE   * sig,
250647e946e7SWyllys Ingersoll 	CK_ULONG    sig_len,
250747e946e7SWyllys Ingersoll 	OBJECT	  * key_obj)
250847e946e7SWyllys Ingersoll {
250947e946e7SWyllys Ingersoll 	TSS_RESULT	result;
251047e946e7SWyllys Ingersoll 	TSS_HHASH	hHash;
251147e946e7SWyllys Ingersoll 	TSS_HKEY	hKey;
251247e946e7SWyllys Ingersoll 	CK_RV		rc;
251347e946e7SWyllys Ingersoll 
251447e946e7SWyllys Ingersoll 	if ((rc = token_rsa_load_key(hContext, key_obj, &hKey))) {
251547e946e7SWyllys Ingersoll 		return (rc);
251647e946e7SWyllys Ingersoll 	}
251747e946e7SWyllys Ingersoll 
251847e946e7SWyllys Ingersoll 	/* Create the hash object we'll use to sign */
251947e946e7SWyllys Ingersoll 	if ((result = Tspi_Context_CreateObject(hContext,
252047e946e7SWyllys Ingersoll 	    TSS_OBJECT_TYPE_HASH, TSS_HASH_OTHER, &hHash))) {
252147e946e7SWyllys Ingersoll 		stlogit("Tspi_Context_CreateObject: 0x%0x - %s",
252247e946e7SWyllys Ingersoll 		    result, Trspi_Error_String(result));
252347e946e7SWyllys Ingersoll 		return (CKR_FUNCTION_FAILED);
252447e946e7SWyllys Ingersoll 	}
252547e946e7SWyllys Ingersoll 
252647e946e7SWyllys Ingersoll 	/* Insert the data into the hash object */
252747e946e7SWyllys Ingersoll 	if ((result = Tspi_Hash_SetHashValue(hHash, in_data_len,
252847e946e7SWyllys Ingersoll 	    in_data))) {
252947e946e7SWyllys Ingersoll 		stlogit("Tspi_Hash_SetHashValue: 0x%0x - %s",
253047e946e7SWyllys Ingersoll 		    result, Trspi_Error_String(result));
253147e946e7SWyllys Ingersoll 		return (CKR_FUNCTION_FAILED);
253247e946e7SWyllys Ingersoll 	}
253347e946e7SWyllys Ingersoll 
253447e946e7SWyllys Ingersoll 	/* Verify */
253547e946e7SWyllys Ingersoll 	result = Tspi_Hash_VerifySignature(hHash, hKey, sig_len, sig);
253647e946e7SWyllys Ingersoll 	if (result != TSS_SUCCESS &&
253747e946e7SWyllys Ingersoll 	    TPMTOK_TSS_ERROR_CODE(result) != TSS_E_FAIL) {
253847e946e7SWyllys Ingersoll 		stlogit("Tspi_Hash_VerifySignature: 0x%0x - %s",
253947e946e7SWyllys Ingersoll 		    result, Trspi_Error_String(result));
254047e946e7SWyllys Ingersoll 	}
254147e946e7SWyllys Ingersoll 
254247e946e7SWyllys Ingersoll 	if (TPMTOK_TSS_ERROR_CODE(result) == TSS_E_FAIL) {
254347e946e7SWyllys Ingersoll 		rc = CKR_SIGNATURE_INVALID;
254447e946e7SWyllys Ingersoll 	} else {
254547e946e7SWyllys Ingersoll 		rc = CKR_OK;
254647e946e7SWyllys Ingersoll 	}
254747e946e7SWyllys Ingersoll 
254847e946e7SWyllys Ingersoll 	return (rc);
254947e946e7SWyllys Ingersoll }
255047e946e7SWyllys Ingersoll 
255147e946e7SWyllys Ingersoll CK_RV
255247e946e7SWyllys Ingersoll token_specific_rsa_sign(
255347e946e7SWyllys Ingersoll 	TSS_HCONTEXT hContext,
255447e946e7SWyllys Ingersoll 	CK_BYTE   * in_data,
255547e946e7SWyllys Ingersoll 	CK_ULONG    in_data_len,
255647e946e7SWyllys Ingersoll 	CK_BYTE   * out_data,
255747e946e7SWyllys Ingersoll 	CK_ULONG  * out_data_len,
255847e946e7SWyllys Ingersoll 	OBJECT	  * key_obj)
255947e946e7SWyllys Ingersoll {
256047e946e7SWyllys Ingersoll 	TSS_RESULT	result;
256147e946e7SWyllys Ingersoll 	TSS_HHASH	hHash;
256247e946e7SWyllys Ingersoll 	BYTE		*sig;
256347e946e7SWyllys Ingersoll 	UINT32		sig_len;
256447e946e7SWyllys Ingersoll 	TSS_HKEY	hKey;
256547e946e7SWyllys Ingersoll 	CK_RV		rc;
256647e946e7SWyllys Ingersoll 
256747e946e7SWyllys Ingersoll 	if ((rc = token_rsa_load_key(hContext, key_obj, &hKey))) {
256847e946e7SWyllys Ingersoll 		return (rc);
256947e946e7SWyllys Ingersoll 	}
257047e946e7SWyllys Ingersoll 
257147e946e7SWyllys Ingersoll 	/* Create the hash object we'll use to sign */
257247e946e7SWyllys Ingersoll 	if ((result = Tspi_Context_CreateObject(hContext,
257347e946e7SWyllys Ingersoll 	    TSS_OBJECT_TYPE_HASH, TSS_HASH_OTHER, &hHash))) {
257447e946e7SWyllys Ingersoll 		stlogit("Tspi_Context_CreateObject: 0x%0x - %s",
257547e946e7SWyllys Ingersoll 		    result, Trspi_Error_String(result));
257647e946e7SWyllys Ingersoll 		return (CKR_FUNCTION_FAILED);
257747e946e7SWyllys Ingersoll 	}
257847e946e7SWyllys Ingersoll 
257947e946e7SWyllys Ingersoll 	/* Insert the data into the hash object */
258047e946e7SWyllys Ingersoll 	if ((result = Tspi_Hash_SetHashValue(hHash, in_data_len,
258147e946e7SWyllys Ingersoll 	    in_data))) {
258247e946e7SWyllys Ingersoll 		stlogit("Tspi_Hash_SetHashValue: 0x%0x - %s",
258347e946e7SWyllys Ingersoll 		    result, Trspi_Error_String(result));
258447e946e7SWyllys Ingersoll 		return (CKR_FUNCTION_FAILED);
258547e946e7SWyllys Ingersoll 	}
258647e946e7SWyllys Ingersoll 
258747e946e7SWyllys Ingersoll 	/* Sign */
258847e946e7SWyllys Ingersoll 	if ((result = Tspi_Hash_Sign(hHash, hKey, &sig_len, &sig))) {
258947e946e7SWyllys Ingersoll 		stlogit("Tspi_Hash_Sign: 0x%0x - %s",
259047e946e7SWyllys Ingersoll 		    result, Trspi_Error_String(result));
2591ab8176c2SWyllys Ingersoll 		return (CKR_DATA_LEN_RANGE);
259247e946e7SWyllys Ingersoll 	}
259347e946e7SWyllys Ingersoll 
259447e946e7SWyllys Ingersoll 	if (sig_len > *out_data_len) {
259547e946e7SWyllys Ingersoll 		Tspi_Context_FreeMemory(hContext, sig);
259647e946e7SWyllys Ingersoll 		return (CKR_BUFFER_TOO_SMALL);
259747e946e7SWyllys Ingersoll 	}
259847e946e7SWyllys Ingersoll 
259947e946e7SWyllys Ingersoll 	(void) memcpy(out_data, sig, sig_len);
260047e946e7SWyllys Ingersoll 	*out_data_len = sig_len;
260147e946e7SWyllys Ingersoll 	Tspi_Context_FreeMemory(hContext, sig);
260247e946e7SWyllys Ingersoll 
260347e946e7SWyllys Ingersoll 	return (CKR_OK);
260447e946e7SWyllys Ingersoll }
260547e946e7SWyllys Ingersoll 
260647e946e7SWyllys Ingersoll CK_RV
260747e946e7SWyllys Ingersoll tpm_encrypt_data(
260847e946e7SWyllys Ingersoll 	TSS_HCONTEXT hContext,
260947e946e7SWyllys Ingersoll 	TSS_HKEY hKey,
261047e946e7SWyllys Ingersoll 	CK_BYTE *in_data,
261147e946e7SWyllys Ingersoll 	CK_ULONG in_data_len,
261247e946e7SWyllys Ingersoll 	CK_BYTE *out_data,
261347e946e7SWyllys Ingersoll 	CK_ULONG *out_data_len)
261447e946e7SWyllys Ingersoll {
261547e946e7SWyllys Ingersoll 	TSS_RESULT	result;
261647e946e7SWyllys Ingersoll 	TSS_HENCDATA	hEncData;
261747e946e7SWyllys Ingersoll 	BYTE		*dataBlob, *modulus;
261847e946e7SWyllys Ingersoll 	UINT32		dataBlobSize, modLen;
261947e946e7SWyllys Ingersoll 	CK_ULONG	chunklen, remain;
262047e946e7SWyllys Ingersoll 	CK_ULONG	outlen;
2621ab8176c2SWyllys Ingersoll 	UINT32		keyusage, scheme, maxsize;
262247e946e7SWyllys Ingersoll 
262347e946e7SWyllys Ingersoll 	if ((result = Tspi_Context_CreateObject(hContext,
262447e946e7SWyllys Ingersoll 	    TSS_OBJECT_TYPE_ENCDATA, TSS_ENCDATA_BIND, &hEncData))) {
262547e946e7SWyllys Ingersoll 		stlogit("Tspi_Context_CreateObject: 0x%0x - %s",
262647e946e7SWyllys Ingersoll 		    result, Trspi_Error_String(result));
262747e946e7SWyllys Ingersoll 		return (CKR_FUNCTION_FAILED);
262847e946e7SWyllys Ingersoll 	}
262947e946e7SWyllys Ingersoll 	/*
263047e946e7SWyllys Ingersoll 	 * Figure out the modulus size so we can break the data
263147e946e7SWyllys Ingersoll 	 * into smaller chunks if necessary.
263247e946e7SWyllys Ingersoll 	 */
263347e946e7SWyllys Ingersoll 	if ((result = Tspi_GetAttribData(hKey, TSS_TSPATTRIB_RSAKEY_INFO,
263447e946e7SWyllys Ingersoll 	    TSS_TSPATTRIB_KEYINFO_RSA_MODULUS, &modLen, &modulus))) {
263547e946e7SWyllys Ingersoll 		stlogit("Tspi_GetAttribData: 0x%0x - %s",
263647e946e7SWyllys Ingersoll 		    result, Trspi_Error_String(result));
263747e946e7SWyllys Ingersoll 		return (result);
263847e946e7SWyllys Ingersoll 	}
263947e946e7SWyllys Ingersoll 	/* we don't need the actual modulus */
264047e946e7SWyllys Ingersoll 	Tspi_Context_FreeMemory(hContext, modulus);
264147e946e7SWyllys Ingersoll 
264247e946e7SWyllys Ingersoll 	/*
264347e946e7SWyllys Ingersoll 	 * According to TSS spec for Tspi_Data_Bind (4.3.4.21.5),
2644ab8176c2SWyllys Ingersoll 	 * Max input data size varies depending on the key type and
2645ab8176c2SWyllys Ingersoll 	 * encryption scheme.
264647e946e7SWyllys Ingersoll 	 */
2647ab8176c2SWyllys Ingersoll 	if ((result = Tspi_GetAttribUint32(hKey, TSS_TSPATTRIB_KEY_INFO,
2648ab8176c2SWyllys Ingersoll 	    TSS_TSPATTRIB_KEYINFO_USAGE, &keyusage))) {
2649ab8176c2SWyllys Ingersoll 		stlogit("Cannot find USAGE: %s\n",
2650ab8176c2SWyllys Ingersoll 		    Trspi_Error_String(result));
2651ab8176c2SWyllys Ingersoll 		return (result);
2652ab8176c2SWyllys Ingersoll 	}
2653ab8176c2SWyllys Ingersoll 	if ((result = Tspi_GetAttribUint32(hKey, TSS_TSPATTRIB_KEY_INFO,
2654ab8176c2SWyllys Ingersoll 	    TSS_TSPATTRIB_KEYINFO_ENCSCHEME, &scheme))) {
2655ab8176c2SWyllys Ingersoll 		stlogit("Cannot find ENCSCHEME: %s\n",
2656ab8176c2SWyllys Ingersoll 		    Trspi_Error_String(result));
2657ab8176c2SWyllys Ingersoll 		return (result);
2658ab8176c2SWyllys Ingersoll 	}
2659ab8176c2SWyllys Ingersoll 	switch (scheme) {
2660ab8176c2SWyllys Ingersoll 		case TSS_ES_RSAESPKCSV15:
2661ab8176c2SWyllys Ingersoll 			if (keyusage == TSS_KEYUSAGE_BIND)
2662ab8176c2SWyllys Ingersoll 				maxsize = 16;
2663ab8176c2SWyllys Ingersoll 			else /* legacy */
2664ab8176c2SWyllys Ingersoll 				maxsize = 11;
2665ab8176c2SWyllys Ingersoll 			break;
2666ab8176c2SWyllys Ingersoll 		case TSS_ES_RSAESOAEP_SHA1_MGF1:
2667ab8176c2SWyllys Ingersoll 			maxsize = 47;
2668ab8176c2SWyllys Ingersoll 			break;
2669ab8176c2SWyllys Ingersoll 		default:
2670ab8176c2SWyllys Ingersoll 			maxsize = 0;
2671ab8176c2SWyllys Ingersoll 	}
2672ab8176c2SWyllys Ingersoll 
2673ab8176c2SWyllys Ingersoll 	modLen -= maxsize;
267447e946e7SWyllys Ingersoll 
267547e946e7SWyllys Ingersoll 	chunklen = (in_data_len > modLen ? modLen : in_data_len);
267647e946e7SWyllys Ingersoll 	remain = in_data_len;
267747e946e7SWyllys Ingersoll 	outlen = 0;
267847e946e7SWyllys Ingersoll 	while (remain > 0) {
267947e946e7SWyllys Ingersoll 		if ((result = Tspi_Data_Bind(hEncData, hKey,
268047e946e7SWyllys Ingersoll 		    chunklen, in_data))) {
268147e946e7SWyllys Ingersoll 			stlogit("Tspi_Data_Bind: 0x%0x - %s",
268247e946e7SWyllys Ingersoll 			    result, Trspi_Error_String(result));
268347e946e7SWyllys Ingersoll 			return (CKR_FUNCTION_FAILED);
268447e946e7SWyllys Ingersoll 		}
268547e946e7SWyllys Ingersoll 
268647e946e7SWyllys Ingersoll 		if ((result = Tspi_GetAttribData(hEncData,
268747e946e7SWyllys Ingersoll 		    TSS_TSPATTRIB_ENCDATA_BLOB,
268847e946e7SWyllys Ingersoll 		    TSS_TSPATTRIB_ENCDATABLOB_BLOB,
268947e946e7SWyllys Ingersoll 		    &dataBlobSize, &dataBlob))) {
269047e946e7SWyllys Ingersoll 			stlogit("Tspi_GetAttribData: 0x%0x - %s",
269147e946e7SWyllys Ingersoll 			    result, Trspi_Error_String(result));
269247e946e7SWyllys Ingersoll 			return (CKR_FUNCTION_FAILED);
269347e946e7SWyllys Ingersoll 		}
269447e946e7SWyllys Ingersoll 
269547e946e7SWyllys Ingersoll 		if (outlen + dataBlobSize > *out_data_len) {
269647e946e7SWyllys Ingersoll 			Tspi_Context_FreeMemory(hContext, dataBlob);
269747e946e7SWyllys Ingersoll 			return (CKR_DATA_LEN_RANGE);
269847e946e7SWyllys Ingersoll 		}
269947e946e7SWyllys Ingersoll 
270047e946e7SWyllys Ingersoll 		(void) memcpy(out_data + outlen,
270147e946e7SWyllys Ingersoll 		    dataBlob, dataBlobSize);
270247e946e7SWyllys Ingersoll 
270347e946e7SWyllys Ingersoll 		outlen += dataBlobSize;
270447e946e7SWyllys Ingersoll 		in_data += chunklen;
270547e946e7SWyllys Ingersoll 		remain -= chunklen;
270647e946e7SWyllys Ingersoll 
270747e946e7SWyllys Ingersoll 		if (chunklen > remain)
270847e946e7SWyllys Ingersoll 			chunklen = remain;
270947e946e7SWyllys Ingersoll 
271047e946e7SWyllys Ingersoll 		Tspi_Context_FreeMemory(hContext, dataBlob);
271147e946e7SWyllys Ingersoll 	}
271247e946e7SWyllys Ingersoll 	*out_data_len = outlen;
271347e946e7SWyllys Ingersoll 
271447e946e7SWyllys Ingersoll 	return (CKR_OK);
271547e946e7SWyllys Ingersoll }
271647e946e7SWyllys Ingersoll 
271747e946e7SWyllys Ingersoll CK_RV
271847e946e7SWyllys Ingersoll token_specific_rsa_encrypt(
271947e946e7SWyllys Ingersoll 	TSS_HCONTEXT hContext,
272047e946e7SWyllys Ingersoll 	CK_BYTE   * in_data,
272147e946e7SWyllys Ingersoll 	CK_ULONG    in_data_len,
272247e946e7SWyllys Ingersoll 	CK_BYTE   * out_data,
272347e946e7SWyllys Ingersoll 	CK_ULONG  * out_data_len,
272447e946e7SWyllys Ingersoll 	OBJECT	  * key_obj)
272547e946e7SWyllys Ingersoll {
272647e946e7SWyllys Ingersoll 	TSS_HKEY	hKey;
272747e946e7SWyllys Ingersoll 	CK_RV		rc;
272847e946e7SWyllys Ingersoll 
272947e946e7SWyllys Ingersoll 	if ((rc = token_rsa_load_key(hContext, key_obj, &hKey))) {
273047e946e7SWyllys Ingersoll 		return (rc);
273147e946e7SWyllys Ingersoll 	}
273247e946e7SWyllys Ingersoll 
273347e946e7SWyllys Ingersoll 	rc  = tpm_encrypt_data(hContext, hKey, in_data, in_data_len,
273447e946e7SWyllys Ingersoll 	    out_data, out_data_len);
273547e946e7SWyllys Ingersoll 
273647e946e7SWyllys Ingersoll 	return (rc);
273747e946e7SWyllys Ingersoll }
2738ab8176c2SWyllys Ingersoll 
2739ab8176c2SWyllys Ingersoll /*
2740ab8176c2SWyllys Ingersoll  * RSA Verify Recover
2741ab8176c2SWyllys Ingersoll  *
2742ab8176c2SWyllys Ingersoll  * Public key crypto is done in software, not by the TPM.
2743ab8176c2SWyllys Ingersoll  * We bypass the TSPI library here in favor of calls directly
2744ab8176c2SWyllys Ingersoll  * to OpenSSL because we don't want to add any padding, the in_data (signature)
2745ab8176c2SWyllys Ingersoll  * already contains the data stream to be decrypted and is already
2746ab8176c2SWyllys Ingersoll  * padded and formatted correctly.
2747ab8176c2SWyllys Ingersoll  */
2748ab8176c2SWyllys Ingersoll CK_RV
2749ab8176c2SWyllys Ingersoll token_specific_rsa_verify_recover(
2750ab8176c2SWyllys Ingersoll 	TSS_HCONTEXT	hContext,
2751ab8176c2SWyllys Ingersoll 	CK_BYTE		*in_data,	/* signature */
2752ab8176c2SWyllys Ingersoll 	CK_ULONG	in_data_len,
2753ab8176c2SWyllys Ingersoll 	CK_BYTE		*out_data,	/* decrypted */
2754ab8176c2SWyllys Ingersoll 	CK_ULONG	*out_data_len,
2755ab8176c2SWyllys Ingersoll 	OBJECT		*key_obj)
2756ab8176c2SWyllys Ingersoll {
2757ab8176c2SWyllys Ingersoll 	TSS_HKEY	hKey;
2758ab8176c2SWyllys Ingersoll 	TSS_RESULT	result;
2759ab8176c2SWyllys Ingersoll 	CK_RV		rc;
2760ab8176c2SWyllys Ingersoll 	BYTE		*modulus;
2761ab8176c2SWyllys Ingersoll 	UINT32		modLen;
2762ab8176c2SWyllys Ingersoll 	RSA		*rsa = NULL;
2763ab8176c2SWyllys Ingersoll 	uchar_t		exp[] = { 0x01, 0x00, 0x01 };
2764ab8176c2SWyllys Ingersoll 	int		sslrv, num;
2765ab8176c2SWyllys Ingersoll 	BYTE		temp[MAX_RSA_KEYLENGTH];
2766*1dc1cb45SWyllys Ingersoll 	BYTE		outdata[MAX_RSA_KEYLENGTH];
2767ab8176c2SWyllys Ingersoll 	int		i;
2768ab8176c2SWyllys Ingersoll 
2769ab8176c2SWyllys Ingersoll 	if ((rc = token_rsa_load_key(hContext, key_obj, &hKey))) {
2770ab8176c2SWyllys Ingersoll 		return (rc);
2771ab8176c2SWyllys Ingersoll 	}
2772ab8176c2SWyllys Ingersoll 
2773ab8176c2SWyllys Ingersoll 	if ((result = Tspi_GetAttribData(hKey, TSS_TSPATTRIB_RSAKEY_INFO,
2774ab8176c2SWyllys Ingersoll 	    TSS_TSPATTRIB_KEYINFO_RSA_MODULUS, &modLen, &modulus))) {
2775ab8176c2SWyllys Ingersoll 		stlogit("Tspi_GetAttribData: 0x%0x - %s",
2776ab8176c2SWyllys Ingersoll 		    result, Trspi_Error_String(result));
2777ab8176c2SWyllys Ingersoll 		return (CKR_FUNCTION_FAILED);
2778ab8176c2SWyllys Ingersoll 	}
2779ab8176c2SWyllys Ingersoll 
2780ab8176c2SWyllys Ingersoll 	if (in_data_len != modLen) {
2781ab8176c2SWyllys Ingersoll 		rc = CKR_SIGNATURE_LEN_RANGE;
2782ab8176c2SWyllys Ingersoll 		goto end;
2783ab8176c2SWyllys Ingersoll 	}
2784ab8176c2SWyllys Ingersoll 
2785ab8176c2SWyllys Ingersoll 	rsa = RSA_new();
2786ab8176c2SWyllys Ingersoll 	if (rsa == NULL) {
2787ab8176c2SWyllys Ingersoll 		rc = CKR_HOST_MEMORY;
2788ab8176c2SWyllys Ingersoll 		goto end;
2789ab8176c2SWyllys Ingersoll 	}
2790ab8176c2SWyllys Ingersoll 
2791ab8176c2SWyllys Ingersoll 	rsa->n = BN_bin2bn(modulus, modLen, rsa->n);
2792ab8176c2SWyllys Ingersoll 	rsa->e = BN_bin2bn(exp, sizeof (exp), rsa->e);
2793ab8176c2SWyllys Ingersoll 	if (rsa->n == NULL || rsa->e == NULL) {
2794ab8176c2SWyllys Ingersoll 		rc = CKR_HOST_MEMORY;
2795ab8176c2SWyllys Ingersoll 		goto end;
2796ab8176c2SWyllys Ingersoll 	}
2797ab8176c2SWyllys Ingersoll 
2798*1dc1cb45SWyllys Ingersoll 	rsa->flags |= RSA_FLAG_SIGN_VER;
2799*1dc1cb45SWyllys Ingersoll 
2800ab8176c2SWyllys Ingersoll 	/* use RSA_NO_PADDING because the data is already padded (PKCS1) */
2801*1dc1cb45SWyllys Ingersoll 	sslrv = RSA_public_encrypt(in_data_len, in_data, outdata,
2802ab8176c2SWyllys Ingersoll 	    rsa, RSA_NO_PADDING);
2803ab8176c2SWyllys Ingersoll 	if (sslrv == -1) {
2804ab8176c2SWyllys Ingersoll 		rc = CKR_FUNCTION_FAILED;
2805ab8176c2SWyllys Ingersoll 		goto end;
2806ab8176c2SWyllys Ingersoll 	}
2807ab8176c2SWyllys Ingersoll 
2808ab8176c2SWyllys Ingersoll 	/* Strip leading 0's before stripping the padding */
2809ab8176c2SWyllys Ingersoll 	for (i = 0; i < sslrv; i++)
2810*1dc1cb45SWyllys Ingersoll 		if (outdata[i] != 0)
2811ab8176c2SWyllys Ingersoll 			break;
2812ab8176c2SWyllys Ingersoll 
2813ab8176c2SWyllys Ingersoll 	num = BN_num_bytes(rsa->n);
2814ab8176c2SWyllys Ingersoll 
2815ab8176c2SWyllys Ingersoll 	/* Use OpenSSL function for stripping PKCS#1 padding */
2816ab8176c2SWyllys Ingersoll 	sslrv = RSA_padding_check_PKCS1_type_1(temp, sizeof (temp),
2817*1dc1cb45SWyllys Ingersoll 	    &outdata[i], sslrv - i, num);
2818ab8176c2SWyllys Ingersoll 
2819ab8176c2SWyllys Ingersoll 	if (sslrv < 0) {
2820ab8176c2SWyllys Ingersoll 		rc = CKR_FUNCTION_FAILED;
2821ab8176c2SWyllys Ingersoll 		goto end;
2822ab8176c2SWyllys Ingersoll 	}
2823ab8176c2SWyllys Ingersoll 
2824ab8176c2SWyllys Ingersoll 	if (*out_data_len < sslrv) {
2825ab8176c2SWyllys Ingersoll 		rc = CKR_BUFFER_TOO_SMALL;
2826ab8176c2SWyllys Ingersoll 		*out_data_len = 0;
2827ab8176c2SWyllys Ingersoll 		goto end;
2828ab8176c2SWyllys Ingersoll 	}
2829ab8176c2SWyllys Ingersoll 
2830ab8176c2SWyllys Ingersoll 	/* The return code indicates the number of bytes remaining */
2831ab8176c2SWyllys Ingersoll 	(void) memcpy(out_data, temp, sslrv);
2832ab8176c2SWyllys Ingersoll 	*out_data_len = sslrv;
2833ab8176c2SWyllys Ingersoll end:
2834ab8176c2SWyllys Ingersoll 	Tspi_Context_FreeMemory(hContext, modulus);
2835ab8176c2SWyllys Ingersoll 	if (rsa)
2836ab8176c2SWyllys Ingersoll 		RSA_free(rsa);
2837ab8176c2SWyllys Ingersoll 
2838ab8176c2SWyllys Ingersoll 	return (rc);
2839ab8176c2SWyllys Ingersoll }
2840