/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "tpmadm.h" int cmd_status(TSS_HCONTEXT hContext, TSS_HTPM hTPM, int argc, char *argv[]); int cmd_init(TSS_HCONTEXT hContext, TSS_HTPM hTPM, int argc, char *argv[]); int cmd_clear(TSS_HCONTEXT hContext, TSS_HTPM hTPM, int argc, char *argv[]); int cmd_auth(TSS_HCONTEXT hContext, TSS_HTPM hTPM, int argc, char *argv[]); int cmd_keyinfo(TSS_HCONTEXT hContext, TSS_HTPM hTPM, int argc, char *argv[]); int cmd_deletekey(TSS_HCONTEXT hContext, TSS_HTPM hTPM, int argc, char *argv[]); cmdtable_t commands[] = { {"status", "", cmd_status}, {"init", "", cmd_init}, {"clear", "[owner | lock]", cmd_clear}, {"auth", "", cmd_auth}, {"keyinfo", "[uuid]", cmd_keyinfo}, {"deletekey", "uuid", cmd_deletekey}, {NULL, NULL, NULL}, }; BYTE well_known[] = TSS_WELL_KNOWN_SECRET; TSS_UUID srk_uuid = TSS_UUID_SRK; /* * TPM status */ static int print_tpm_version(TSS_HCONTEXT hContext, TSS_HOBJECT hTPM) { struct { TPM_CAP_VERSION_INFO vers_info; char extra[20]; /* vendor extensions */ } info; if (get_tpm_capability(hContext, hTPM, TSS_TPMCAP_VERSION_VAL, 0, &info, sizeof (info))) return (ERR_FAIL); (void) printf(gettext("TPM Version: %d.%d (%c%c%c%c Rev: %d.%d, " "SpecLevel: %d, ErrataRev: %d)\n"), info.vers_info.version.major, info.vers_info.version.minor, info.vers_info.tpmVendorID[0], info.vers_info.tpmVendorID[1], info.vers_info.tpmVendorID[2], info.vers_info.tpmVendorID[3], info.vers_info.version.revMajor, info.vers_info.version.revMinor, (int)ntohs(info.vers_info.specLevel), info.vers_info.errataRev); return (0); } static int tpm_is_owned(TSS_HCONTEXT hContext, TSS_HOBJECT hTPM) { BYTE owned; if (get_tpm_capability(hContext, hTPM, TSS_TPMCAP_PROPERTY, TSS_TPMCAP_PROP_OWNER, &owned, sizeof (owned))) return (0); return (owned); } static int print_tpm_resources(TSS_HCONTEXT hContext, TSS_HOBJECT hTPM) { UINT32 avail, max; (void) printf(gettext("TPM resources\n")); if (get_tpm_capability(hContext, hTPM, TSS_TPMCAP_PROPERTY, TSS_TPMCAP_PROP_MAXCONTEXTS, &max, sizeof (max))) return (ERR_FAIL); if (get_tpm_capability(hContext, hTPM, TSS_TPMCAP_PROPERTY, TSS_TPMCAP_PROP_CONTEXTS, &avail, sizeof (avail))) return (ERR_FAIL); (void) printf(gettext("\tContexts: %d/%d available\n"), avail, max); if (get_tpm_capability(hContext, hTPM, TSS_TPMCAP_PROPERTY, TSS_TPMCAP_PROP_MAXSESSIONS, &max, sizeof (max))) return (ERR_FAIL); if (get_tpm_capability(hContext, hTPM, TSS_TPMCAP_PROPERTY, TSS_TPMCAP_PROP_SESSIONS, &avail, sizeof (avail))) return (ERR_FAIL); (void) printf(gettext("\tSessions: %d/%d available\n"), avail, max); if (get_tpm_capability(hContext, hTPM, TSS_TPMCAP_PROPERTY, TSS_TPMCAP_PROP_MAXAUTHSESSIONS, &max, sizeof (max))) return (ERR_FAIL); if (get_tpm_capability(hContext, hTPM, TSS_TPMCAP_PROPERTY, TSS_TPMCAP_PROP_AUTHSESSIONS, &avail, sizeof (avail))) return (ERR_FAIL); (void) printf(gettext("\tAuth Sessions: %d/%d available\n"), avail, max); if (get_tpm_capability(hContext, hTPM, TSS_TPMCAP_PROPERTY, TSS_TPMCAP_PROP_MAXKEYS, &max, sizeof (max))) return (ERR_FAIL); if (get_tpm_capability(hContext, hTPM, TSS_TPMCAP_PROPERTY, TSS_TPMCAP_PROP_KEYS, &avail, sizeof (avail))) return (ERR_FAIL); (void) printf(gettext("\tLoaded Keys: %d/%d available\n"), avail, max); return (0); } static int print_tpm_pcrs(TSS_HCONTEXT hContext, TSS_HOBJECT hTPM) { UINT32 num_pcrs; int i; if (get_tpm_capability(hContext, hTPM, TSS_TPMCAP_PROPERTY, TSS_TPMCAP_PROP_PCR, &num_pcrs, sizeof (num_pcrs))) return (ERR_FAIL); (void) printf(gettext("Platform Configuration Registers (%u)\n"), num_pcrs); /* Print each PCR */ for (i = 0; i < num_pcrs; i++) { TSS_RESULT ret; UINT32 datalen; BYTE *data; ret = Tspi_TPM_PcrRead(hTPM, i, &datalen, &data); if (ret) { print_error(ret, gettext("Read PCR")); return (ret); } (void) printf("\tPCR %u:\t", i); print_bytes(data, datalen, FALSE); ret = Tspi_Context_FreeMemory(hContext, data); if (ret) { print_error(ret, gettext("Free PCR memory")); return (ret); } } return (0); } /*ARGSUSED*/ int cmd_status(TSS_HCONTEXT hContext, TSS_HTPM hTPM, int argc, char *argv[]) { if (set_object_policy(hTPM, TSS_SECRET_MODE_POPUP, 0, NULL)) return (ERR_FAIL); (void) print_tpm_version(hContext, hTPM); if (tpm_is_owned(hContext, hTPM)) { (void) print_tpm_resources(hContext, hTPM); (void) print_tpm_pcrs(hContext, hTPM); } else { (void) printf(gettext("No TPM owner installed.\n")); } return (0); } /* * Key Information */ typedef struct { UINT32 code; char *str; } decode_map_t; decode_map_t key_usage[] = { { TSS_KEYUSAGE_SIGN, "Signing" }, { TSS_KEYUSAGE_STORAGE, "Storage" }, { TSS_KEYUSAGE_IDENTITY, "Identity" }, { TSS_KEYUSAGE_AUTHCHANGE, "Authchange" }, { TSS_KEYUSAGE_BIND, "Bind" }, { TSS_KEYUSAGE_LEGACY, "Legacy" }, { TSS_KEYUSAGE_MIGRATE, "Migrate" }, { 0, NULL }, }; decode_map_t key_algorithm[] = { { TSS_ALG_RSA, "RSA" }, { TSS_ALG_DES, "DES" }, { TSS_ALG_3DES, "3-DES" }, { TSS_ALG_SHA, "SHA" }, { TSS_ALG_HMAC, "HMAC" }, { TSS_ALG_AES, "AES" }, { TSS_ALG_MGF1, "MGF1" }, { TSS_ALG_AES192, "AES192" }, { TSS_ALG_AES256, "AES256" }, { TSS_ALG_XOR, "XOR" }, { 0, NULL }, }; decode_map_t key_sigscheme[] = { { TSS_SS_NONE, "None" }, { TSS_SS_RSASSAPKCS1V15_SHA1, "RSASSAPKCS1v15_SHA1" }, { TSS_SS_RSASSAPKCS1V15_DER, "RSASSAPKCS1v15_DER" }, { 0, NULL }, }; decode_map_t key_encscheme[] = { { TSS_ES_NONE, "None" }, { TSS_ES_RSAESPKCSV15, "RSAESPKCSv15" }, { TSS_ES_RSAESOAEP_SHA1_MGF1, "RSAESOAEP_SHA1_MGF1" }, { TSS_ES_SYM_CNT, "SYM_CNT" }, { TSS_ES_SYM_OFB, "SYM_OFB" }, { 0, NULL }, }; static char * decode(decode_map_t *table, UINT32 code) { static char buf[20]; int i; for (i = 0; table[i].str != NULL; i++) { if (table[i].code == code) return (table[i].str); } (void) snprintf(buf, sizeof (buf), gettext("Unknown (%u)"), code); return (buf); } static void print_key_info(TSS_HCONTEXT hContext, TSS_HOBJECT hKey) { TSS_RESULT ret; UINT32 attrib; UINT32 keyInfoSize; BYTE *keyInfo; /* Key size */ ret = Tspi_GetAttribUint32(hKey, TSS_TSPATTRIB_KEY_INFO, TSS_TSPATTRIB_KEYINFO_SIZE, &attrib); if (ret) { print_error(ret, gettext("Get key size")); } (void) printf(gettext("Key Size: %d bits\n"), attrib); /* Key usage */ ret = Tspi_GetAttribUint32(hKey, TSS_TSPATTRIB_KEY_INFO, TSS_TSPATTRIB_KEYINFO_USAGE, &attrib); if (ret) { print_error(ret, gettext("Get key usage")); } (void) printf(gettext("Key Usage: %s\n"), decode(key_usage, attrib)); /* Algorithm */ ret = Tspi_GetAttribUint32(hKey, TSS_TSPATTRIB_KEY_INFO, TSS_TSPATTRIB_KEYINFO_ALGORITHM, &attrib); if (ret) { print_error(ret, gettext("Get key algorithm")); } (void) printf(gettext("Algorithm: %s\n"), decode(key_algorithm, attrib)); /* Authorization required */ ret = Tspi_GetAttribUint32(hKey, TSS_TSPATTRIB_KEY_INFO, TSS_TSPATTRIB_KEYINFO_AUTHUSAGE, &attrib); if (ret) { print_error(ret, gettext("Get key authusage")); } (void) printf(gettext("Authorization required: %s\n"), attrib ? gettext("Yes") : gettext("No")); /* Signature scheme */ ret = Tspi_GetAttribUint32(hKey, TSS_TSPATTRIB_KEY_INFO, TSS_TSPATTRIB_KEYINFO_SIGSCHEME, &attrib); if (ret) { print_error(ret, gettext("Get key signature scheme")); } (void) printf(gettext("Signature scheme: %s\n"), decode(key_sigscheme, attrib)); /* Encoding scheme */ ret = Tspi_GetAttribUint32(hKey, TSS_TSPATTRIB_KEY_INFO, TSS_TSPATTRIB_KEYINFO_ENCSCHEME, &attrib); if (ret) { print_error(ret, gettext("Get key encoding scheme")); } (void) printf(gettext("Encoding scheme: %s\n"), decode(key_encscheme, attrib)); /* Key blob */ ret = Tspi_GetAttribData(hKey, TSS_TSPATTRIB_KEY_BLOB, TSS_TSPATTRIB_KEYBLOB_BLOB, &keyInfoSize, &keyInfo); if (ret) { print_error(ret, gettext("Get key blob")); } (void) printf(gettext("TPM Key Blob:\n")); print_bytes(keyInfo, keyInfoSize, TRUE); ret = Tspi_Context_FreeMemory(hContext, keyInfo); if (ret) { print_error(ret, gettext("Free key info buffer")); } } typedef struct hash_node { struct hash_node *next, *sibling, *child; TSS_UUID uuid; TSS_KM_KEYINFO2 *key_data; } hash_node_t; #define HASHSIZE 17 hash_node_t *hash_table[HASHSIZE]; static hash_node_t * hash_insert(TSS_UUID uuid, TSS_KM_KEYINFO2 *key_data) { UINT32 i, index = 0; hash_node_t *node; char *cp; cp = (char *)&uuid; for (i = 0; i < sizeof (TSS_UUID); i++) index += cp[i]; index = index % HASHSIZE; for (node = hash_table[index]; node != NULL; node = node->next) { if (memcmp(&(node->uuid), &uuid, sizeof (TSS_UUID)) == 0) break; } if (node == NULL) { node = calloc(1, sizeof (hash_node_t)); node->uuid = uuid; node->next = hash_table[index]; hash_table[index] = node; } if (node->key_data == NULL) node->key_data = key_data; return (node); } static void add_child(hash_node_t *parent, hash_node_t *child) { hash_node_t *node; for (node = parent->child; node != NULL; node = node->next) { if (node == child) return; } child->sibling = parent->child; parent->child = child; } static void print_all(hash_node_t *parent, int indent) { char uuidstr[UUID_PRINTABLE_STRING_LENGTH]; hash_node_t *node; char *type, *loaded; uuid_unparse(*(uuid_t *)&parent->uuid, uuidstr); type = (parent->key_data->persistentStorageType == TSS_PS_TYPE_USER) ? "USER" : "SYSTEM"; loaded = parent->key_data->fIsLoaded ? "(loaded)" : ""; (void) printf("%*s[%s] %s %s\n", indent, "", type, uuidstr, loaded); for (node = parent->child; node != NULL; node = node->sibling) print_all(node, indent + 4); } /*ARGSUSED*/ int cmd_keyinfo(TSS_HCONTEXT hContext, TSS_HTPM hTPM, int argc, char *argv[]) { TSS_RESULT ret; UINT32 i, num_keys; TSS_KM_KEYINFO2 *keys; hash_node_t *parent, *child, *srk = NULL; TSS_HKEY hKey; union { uuid_t arr_uuid; TSS_UUID tss_uuid; } uuid; switch (argc) { case 1: /* Print key hierarchy */ ret = Tspi_Context_GetRegisteredKeysByUUID2(hContext, TSS_PS_TYPE_USER, NULL, &num_keys, &keys); if (ret) { print_error(ret, gettext("Get key hierarchy")); return (ERR_FAIL); } for (i = 0; i < num_keys; i++) { parent = hash_insert(keys[i].parentKeyUUID, NULL); child = hash_insert(keys[i].keyUUID, &keys[i]); add_child(parent, child); if (memcmp(&(keys[i].keyUUID), &srk_uuid, sizeof (TSS_UUID)) == 0) srk = child; } if (srk != NULL) print_all(srk, 0); ret = Tspi_Context_FreeMemory(hContext, (BYTE *) keys); if (ret) { print_error(ret, gettext("Free key list")); return (ERR_FAIL); } return (0); case 2: /* Print detailed info about a single key */ if (uuid_parse(argv[1], uuid.arr_uuid)) return (ERR_FAIL); ret = Tspi_Context_GetKeyByUUID(hContext, TSS_PS_TYPE_USER, uuid.tss_uuid, &hKey); if (ret == TSP_ERROR(TSS_E_PS_KEY_NOTFOUND)) { ret = Tspi_Context_GetKeyByUUID(hContext, TSS_PS_TYPE_SYSTEM, uuid.tss_uuid, &hKey); } if (ret) { print_error(ret, gettext("Get key by UUID")); return (ERR_FAIL); } print_key_info(hContext, hKey); return (0); default: (void) fprintf(stderr, gettext("Usage:\n")); (void) fprintf(stderr, "\tkeyinfo [uuid]\n"); return (ERR_USAGE); } } /*ARGSUSED*/ int cmd_deletekey(TSS_HCONTEXT hContext, TSS_HTPM hTPM, int argc, char *argv[]) { TSS_RESULT ret; TSS_HOBJECT hKey; union { uuid_t arr_uuid; TSS_UUID tss_uuid; } uuid; if (argc < 2) { (void) fprintf(stderr, gettext("Usage:\n")); (void) fprintf(stderr, "\tdeletekey [uuid]\n"); return (ERR_USAGE); } if (uuid_parse(argv[1], uuid.arr_uuid)) return (ERR_FAIL); ret = Tspi_Context_UnregisterKey(hContext, TSS_PS_TYPE_USER, uuid.tss_uuid, &hKey); if (ret == TSP_ERROR(TSS_E_PS_KEY_NOTFOUND)) { ret = Tspi_Context_UnregisterKey(hContext, TSS_PS_TYPE_SYSTEM, uuid.tss_uuid, &hKey); } if (ret) { print_error(ret, gettext("Unregister key")); return (ERR_FAIL); } return (0); } /* * Clear */ static int clearowner(TSS_HTPM hTPM) { TSS_RESULT ret; if (set_object_policy(hTPM, TSS_SECRET_MODE_POPUP, 0, NULL)) return (ERR_FAIL); ret = Tspi_TPM_ClearOwner(hTPM, FALSE); if (ret) { print_error(ret, gettext("Clear TPM owner")); return (ERR_FAIL); } return (0); } static int resetlock(TSS_HTPM hTPM) { TSS_RESULT ret; if (set_object_policy(hTPM, TSS_SECRET_MODE_POPUP, 0, NULL)) return (ERR_FAIL); ret = Tspi_TPM_SetStatus(hTPM, TSS_TPMSTATUS_RESETLOCK, TRUE); if (ret) { print_error(ret, gettext("Reset Lock")); return (ERR_FAIL); } return (0); } /*ARGSUSED*/ int cmd_clear(TSS_HCONTEXT hContext, TSS_HTPM hTPM, int argc, char *argv[]) { char *subcmd = argv[1]; if (subcmd && strcmp(subcmd, "lock") == 0) { return (resetlock(hTPM)); } else if (subcmd && strcmp(subcmd, "owner") == 0) { return (clearowner(hTPM)); } else { (void) fprintf(stderr, gettext("Usage:\n")); (void) fprintf(stderr, "\tclear owner\n"); (void) fprintf(stderr, "\tclear lock\n"); return (ERR_USAGE); } } /* * TPM initialization */ static int get_random(UINT32 size, BYTE *randomBytes) { int fd, len; BYTE *buf; fd = open("/dev/random", O_RDONLY); if (fd == -1) { (void) fprintf(stderr, gettext("Unable to open /dev/random")); return (-1); } buf = randomBytes; while (size > 0) { len = read(fd, buf, size); if (len <= 0) { (void) close(fd); (void) fprintf(stderr, gettext("Error reading /dev/random")); return (-1); } size -= len; buf += len; } (void) close(fd); return (0); } static int createek(TSS_HCONTEXT hContext, TSS_HTPM hTPM) { TSS_RESULT ret; TSS_HOBJECT hKeyEK; TSS_VALIDATION ValidationData; TPM_NONCE nonce; TPM_DIGEST digest; /* Create the empty key struct for EK */ ret = Tspi_Context_CreateObject(hContext, TSS_OBJECT_TYPE_RSAKEY, (TSS_KEY_NO_AUTHORIZATION | TSS_KEY_NON_VOLATILE | TSS_KEY_NOT_MIGRATABLE | TSS_KEY_TYPE_STORAGE | TSS_KEY_SIZE_2048 | TSS_KEY_NOT_CERTIFIED_MIGRATABLE | TSS_KEY_STRUCT_KEY12 | TSS_KEY_EMPTY_KEY), &hKeyEK); if (ret) { print_error(ret, gettext("Create endorsement key object")); return (ERR_FAIL); } ValidationData.ulExternalDataLength = sizeof (nonce); ValidationData.rgbExternalData = (BYTE *) &nonce; ret = get_random(sizeof (nonce), (BYTE *) &nonce); if (ret) return (ERR_FAIL); ValidationData.ulValidationDataLength = sizeof (digest); ValidationData.rgbValidationData = (BYTE *) &digest; ret = Tspi_TPM_CreateEndorsementKey(hTPM, hKeyEK, &ValidationData); if (ret) { print_error(ret, gettext("Create endorsement key")); return (ERR_FAIL); } return (0); } /*ARGSUSED*/ int cmd_init(TSS_HCONTEXT hContext, TSS_HTPM hTPM, int argc, char *argv[]) { TSS_RESULT ret; TSS_HOBJECT hKeySRK; if (set_object_policy(hTPM, TSS_SECRET_MODE_POPUP, 0, NULL)) return (ERR_FAIL); ret = Tspi_Context_CreateObject(hContext, TSS_OBJECT_TYPE_RSAKEY, TSS_KEY_TSP_SRK | TSS_KEY_AUTHORIZATION, &hKeySRK); if (ret) { print_error(ret, gettext("Create storage root key")); return (ERR_FAIL); } if (set_object_policy(hKeySRK, TSS_SECRET_MODE_SHA1, sizeof (well_known), well_known)) return (ERR_FAIL); ret = Tspi_TPM_TakeOwnership(hTPM, hKeySRK, NULL); if (ret == TPM_E_NO_ENDORSEMENT) { if (createek(hContext, hTPM)) return (ERR_FAIL); ret = Tspi_TPM_TakeOwnership(hTPM, hKeySRK, NULL); } if (ret) { print_error(ret, gettext("Take ownership")); return (ERR_FAIL); } return (0); } /* * Auth */ /*ARGSUSED*/ int cmd_auth(TSS_HCONTEXT hContext, TSS_HTPM hTPM, int argc, char *argv[]) { TSS_RESULT ret; TSS_HPOLICY hNewPolicy; if (set_object_policy(hTPM, TSS_SECRET_MODE_POPUP, 0, NULL)) return (ERR_FAIL); /* new policy object */ ret = Tspi_Context_CreateObject(hContext, TSS_OBJECT_TYPE_POLICY, TSS_POLICY_USAGE, &hNewPolicy); if (ret) { print_error(ret, gettext("Create policy object")); return (ERR_FAIL); } ret = Tspi_Policy_SetSecret(hNewPolicy, TSS_SECRET_MODE_POPUP, 0, NULL); if (ret) { print_error(ret, gettext("Set policy object secret")); return (ERR_FAIL); } ret = Tspi_ChangeAuth(hTPM, NULL, hNewPolicy); if (ret) { print_error(ret, gettext("Change authorization")); return (ERR_FAIL); } return (0); }