2014-12-12 22:46:38 +03:00
/*
2015-05-30 08:09:04 +03:00
* Copyright ( C ) 2014 , 2015 Intel Corporation
2014-12-12 22:46:38 +03:00
*
* Authors :
* Jarkko Sakkinen < jarkko . sakkinen @ linux . intel . com >
*
* Maintained by : < tpmdd - devel @ lists . sourceforge . net >
*
* This file contains TPM2 protocol implementations of the commands
* used by the kernel internally .
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; version 2
* of the License .
*/
# include "tpm.h"
2015-11-05 22:43:06 +03:00
# include <crypto/hash_info.h>
2015-05-30 08:09:04 +03:00
# include <keys/trusted-type.h>
enum tpm2_object_attributes {
2016-02-13 12:51:23 +03:00
TPM2_OA_USER_WITH_AUTH = BIT ( 6 ) ,
} ;
enum tpm2_session_attributes {
TPM2_SA_CONTINUE_SESSION = BIT ( 0 ) ,
2015-05-30 08:09:04 +03:00
} ;
2014-12-12 22:46:38 +03:00
struct tpm2_startup_in {
__be16 startup_type ;
} __packed ;
struct tpm2_self_test_in {
u8 full_test ;
} __packed ;
struct tpm2_pcr_read_in {
__be32 pcr_selects_cnt ;
__be16 hash_alg ;
u8 pcr_select_size ;
u8 pcr_select [ TPM2_PCR_SELECT_MIN ] ;
} __packed ;
struct tpm2_pcr_read_out {
__be32 update_cnt ;
__be32 pcr_selects_cnt ;
__be16 hash_alg ;
u8 pcr_select_size ;
u8 pcr_select [ TPM2_PCR_SELECT_MIN ] ;
__be32 digests_cnt ;
__be16 digest_size ;
u8 digest [ TPM_DIGEST_SIZE ] ;
} __packed ;
struct tpm2_get_tpm_pt_in {
__be32 cap_id ;
__be32 property_id ;
__be32 property_cnt ;
} __packed ;
struct tpm2_get_tpm_pt_out {
u8 more_data ;
__be32 subcap_id ;
__be32 property_cnt ;
__be32 property_id ;
__be32 value ;
} __packed ;
struct tpm2_get_random_in {
__be16 size ;
} __packed ;
struct tpm2_get_random_out {
__be16 size ;
u8 buffer [ TPM_MAX_RNG_DATA ] ;
} __packed ;
union tpm2_cmd_params {
struct tpm2_startup_in startup_in ;
struct tpm2_self_test_in selftest_in ;
struct tpm2_pcr_read_in pcrread_in ;
struct tpm2_pcr_read_out pcrread_out ;
struct tpm2_get_tpm_pt_in get_tpm_pt_in ;
struct tpm2_get_tpm_pt_out get_tpm_pt_out ;
struct tpm2_get_random_in getrandom_in ;
struct tpm2_get_random_out getrandom_out ;
} ;
struct tpm2_cmd {
tpm_cmd_header header ;
union tpm2_cmd_params params ;
} __packed ;
2015-11-05 22:43:06 +03:00
struct tpm2_hash {
unsigned int crypto_id ;
unsigned int tpm_id ;
} ;
static struct tpm2_hash tpm2_hash_map [ ] = {
{ HASH_ALGO_SHA1 , TPM2_ALG_SHA1 } ,
{ HASH_ALGO_SHA256 , TPM2_ALG_SHA256 } ,
{ HASH_ALGO_SHA384 , TPM2_ALG_SHA384 } ,
{ HASH_ALGO_SHA512 , TPM2_ALG_SHA512 } ,
{ HASH_ALGO_SM3_256 , TPM2_ALG_SM3_256 } ,
} ;
2014-12-12 22:46:38 +03:00
/*
* Array with one entry per ordinal defining the maximum amount
* of time the chip could take to return the result . The values
* of the SHORT , MEDIUM , and LONG durations are taken from the
* PC Client Profile ( PTP ) specification .
*/
static const u8 tpm2_ordinal_duration [ TPM2_CC_LAST - TPM2_CC_FIRST + 1 ] = {
TPM_UNDEFINED , /* 11F */
TPM_UNDEFINED , /* 120 */
TPM_LONG , /* 121 */
TPM_UNDEFINED , /* 122 */
TPM_UNDEFINED , /* 123 */
TPM_UNDEFINED , /* 124 */
TPM_UNDEFINED , /* 125 */
TPM_UNDEFINED , /* 126 */
TPM_UNDEFINED , /* 127 */
TPM_UNDEFINED , /* 128 */
TPM_LONG , /* 129 */
TPM_UNDEFINED , /* 12a */
TPM_UNDEFINED , /* 12b */
TPM_UNDEFINED , /* 12c */
TPM_UNDEFINED , /* 12d */
TPM_UNDEFINED , /* 12e */
TPM_UNDEFINED , /* 12f */
TPM_UNDEFINED , /* 130 */
TPM_UNDEFINED , /* 131 */
TPM_UNDEFINED , /* 132 */
TPM_UNDEFINED , /* 133 */
TPM_UNDEFINED , /* 134 */
TPM_UNDEFINED , /* 135 */
TPM_UNDEFINED , /* 136 */
TPM_UNDEFINED , /* 137 */
TPM_UNDEFINED , /* 138 */
TPM_UNDEFINED , /* 139 */
TPM_UNDEFINED , /* 13a */
TPM_UNDEFINED , /* 13b */
TPM_UNDEFINED , /* 13c */
TPM_UNDEFINED , /* 13d */
TPM_MEDIUM , /* 13e */
TPM_UNDEFINED , /* 13f */
TPM_UNDEFINED , /* 140 */
TPM_UNDEFINED , /* 141 */
TPM_UNDEFINED , /* 142 */
TPM_LONG , /* 143 */
TPM_MEDIUM , /* 144 */
TPM_UNDEFINED , /* 145 */
TPM_UNDEFINED , /* 146 */
TPM_UNDEFINED , /* 147 */
TPM_UNDEFINED , /* 148 */
TPM_UNDEFINED , /* 149 */
TPM_UNDEFINED , /* 14a */
TPM_UNDEFINED , /* 14b */
TPM_UNDEFINED , /* 14c */
TPM_UNDEFINED , /* 14d */
TPM_LONG , /* 14e */
TPM_UNDEFINED , /* 14f */
TPM_UNDEFINED , /* 150 */
TPM_UNDEFINED , /* 151 */
TPM_UNDEFINED , /* 152 */
TPM_UNDEFINED , /* 153 */
TPM_UNDEFINED , /* 154 */
TPM_UNDEFINED , /* 155 */
TPM_UNDEFINED , /* 156 */
TPM_UNDEFINED , /* 157 */
TPM_UNDEFINED , /* 158 */
TPM_UNDEFINED , /* 159 */
TPM_UNDEFINED , /* 15a */
TPM_UNDEFINED , /* 15b */
TPM_MEDIUM , /* 15c */
TPM_UNDEFINED , /* 15d */
TPM_UNDEFINED , /* 15e */
TPM_UNDEFINED , /* 15f */
TPM_UNDEFINED , /* 160 */
TPM_UNDEFINED , /* 161 */
TPM_UNDEFINED , /* 162 */
TPM_UNDEFINED , /* 163 */
TPM_UNDEFINED , /* 164 */
TPM_UNDEFINED , /* 165 */
TPM_UNDEFINED , /* 166 */
TPM_UNDEFINED , /* 167 */
TPM_UNDEFINED , /* 168 */
TPM_UNDEFINED , /* 169 */
TPM_UNDEFINED , /* 16a */
TPM_UNDEFINED , /* 16b */
TPM_UNDEFINED , /* 16c */
TPM_UNDEFINED , /* 16d */
TPM_UNDEFINED , /* 16e */
TPM_UNDEFINED , /* 16f */
TPM_UNDEFINED , /* 170 */
TPM_UNDEFINED , /* 171 */
TPM_UNDEFINED , /* 172 */
TPM_UNDEFINED , /* 173 */
TPM_UNDEFINED , /* 174 */
TPM_UNDEFINED , /* 175 */
TPM_UNDEFINED , /* 176 */
TPM_LONG , /* 177 */
TPM_UNDEFINED , /* 178 */
TPM_UNDEFINED , /* 179 */
TPM_MEDIUM , /* 17a */
TPM_LONG , /* 17b */
TPM_UNDEFINED , /* 17c */
TPM_UNDEFINED , /* 17d */
TPM_UNDEFINED , /* 17e */
TPM_UNDEFINED , /* 17f */
TPM_UNDEFINED , /* 180 */
TPM_UNDEFINED , /* 181 */
TPM_MEDIUM , /* 182 */
TPM_UNDEFINED , /* 183 */
TPM_UNDEFINED , /* 184 */
TPM_MEDIUM , /* 185 */
TPM_MEDIUM , /* 186 */
TPM_UNDEFINED , /* 187 */
TPM_UNDEFINED , /* 188 */
TPM_UNDEFINED , /* 189 */
TPM_UNDEFINED , /* 18a */
TPM_UNDEFINED , /* 18b */
TPM_UNDEFINED , /* 18c */
TPM_UNDEFINED , /* 18d */
TPM_UNDEFINED , /* 18e */
TPM_UNDEFINED /* 18f */
} ;
# define TPM2_PCR_READ_IN_SIZE \
( sizeof ( struct tpm_input_header ) + \
sizeof ( struct tpm2_pcr_read_in ) )
2017-01-19 15:19:12 +03:00
# define TPM2_PCR_READ_RESP_BODY_SIZE \
sizeof ( struct tpm2_pcr_read_out )
2014-12-12 22:46:38 +03:00
static const struct tpm_input_header tpm2_pcrread_header = {
. tag = cpu_to_be16 ( TPM2_ST_NO_SESSIONS ) ,
. length = cpu_to_be32 ( TPM2_PCR_READ_IN_SIZE ) ,
. ordinal = cpu_to_be32 ( TPM2_CC_PCR_READ )
} ;
/**
* tpm2_pcr_read ( ) - read a PCR value
* @ chip : TPM chip to use .
* @ pcr_idx : index of the PCR to read .
2016-11-23 13:04:12 +03:00
* @ res_buf : buffer to store the resulting hash .
2014-12-12 22:46:38 +03:00
*
2016-11-23 13:04:12 +03:00
* Return : Same as with tpm_transmit_cmd .
2014-12-12 22:46:38 +03:00
*/
int tpm2_pcr_read ( struct tpm_chip * chip , int pcr_idx , u8 * res_buf )
{
int rc ;
struct tpm2_cmd cmd ;
u8 * buf ;
if ( pcr_idx > = TPM2_PLATFORM_PCR )
return - EINVAL ;
cmd . header . in = tpm2_pcrread_header ;
cmd . params . pcrread_in . pcr_selects_cnt = cpu_to_be32 ( 1 ) ;
cmd . params . pcrread_in . hash_alg = cpu_to_be16 ( TPM2_ALG_SHA1 ) ;
cmd . params . pcrread_in . pcr_select_size = TPM2_PCR_SELECT_MIN ;
memset ( cmd . params . pcrread_in . pcr_select , 0 ,
sizeof ( cmd . params . pcrread_in . pcr_select ) ) ;
cmd . params . pcrread_in . pcr_select [ pcr_idx > > 3 ] = 1 < < ( pcr_idx & 0x7 ) ;
2017-01-06 15:03:45 +03:00
rc = tpm_transmit_cmd ( chip , NULL , & cmd , sizeof ( cmd ) ,
2017-01-19 15:19:12 +03:00
TPM2_PCR_READ_RESP_BODY_SIZE ,
0 , " attempting to read a pcr value " ) ;
2014-12-12 22:46:38 +03:00
if ( rc = = 0 ) {
buf = cmd . params . pcrread_out . digest ;
memcpy ( res_buf , buf , TPM_DIGEST_SIZE ) ;
}
return rc ;
}
2017-01-30 12:59:41 +03:00
struct tpm2_null_auth_area {
__be32 handle ;
__be16 nonce_size ;
u8 attributes ;
__be16 auth_size ;
} __packed ;
2014-12-12 22:46:38 +03:00
/**
* tpm2_pcr_extend ( ) - extend a PCR value
2016-11-23 13:04:12 +03:00
*
2014-12-12 22:46:38 +03:00
* @ chip : TPM chip to use .
* @ pcr_idx : index of the PCR .
2017-01-30 12:59:41 +03:00
* @ count : number of digests passed .
* @ digests : list of pcr banks and corresponding digest values to extend .
2014-12-12 22:46:38 +03:00
*
2016-11-23 13:04:12 +03:00
* Return : Same as with tpm_transmit_cmd .
2014-12-12 22:46:38 +03:00
*/
2017-01-30 12:59:41 +03:00
int tpm2_pcr_extend ( struct tpm_chip * chip , int pcr_idx , u32 count ,
struct tpm2_digest * digests )
2014-12-12 22:46:38 +03:00
{
2017-01-30 12:59:41 +03:00
struct tpm_buf buf ;
struct tpm2_null_auth_area auth_area ;
2014-12-12 22:46:38 +03:00
int rc ;
2017-01-30 12:59:41 +03:00
int i ;
int j ;
2014-12-12 22:46:38 +03:00
2017-01-30 12:59:41 +03:00
if ( count > ARRAY_SIZE ( chip - > active_banks ) )
return - EINVAL ;
2014-12-12 22:46:38 +03:00
2017-01-30 12:59:41 +03:00
rc = tpm_buf_init ( & buf , TPM2_ST_SESSIONS , TPM2_CC_PCR_EXTEND ) ;
if ( rc )
return rc ;
tpm_buf_append_u32 ( & buf , pcr_idx ) ;
auth_area . handle = cpu_to_be32 ( TPM2_RS_PW ) ;
auth_area . nonce_size = 0 ;
auth_area . attributes = 0 ;
auth_area . auth_size = 0 ;
tpm_buf_append_u32 ( & buf , sizeof ( struct tpm2_null_auth_area ) ) ;
tpm_buf_append ( & buf , ( const unsigned char * ) & auth_area ,
sizeof ( auth_area ) ) ;
tpm_buf_append_u32 ( & buf , count ) ;
for ( i = 0 ; i < count ; i + + ) {
for ( j = 0 ; j < ARRAY_SIZE ( tpm2_hash_map ) ; j + + ) {
if ( digests [ i ] . alg_id ! = tpm2_hash_map [ j ] . tpm_id )
continue ;
tpm_buf_append_u16 ( & buf , digests [ i ] . alg_id ) ;
tpm_buf_append ( & buf , ( const unsigned char
* ) & digests [ i ] . digest ,
hash_digest_size [ tpm2_hash_map [ j ] . crypto_id ] ) ;
}
}
2017-01-06 15:03:45 +03:00
rc = tpm_transmit_cmd ( chip , NULL , buf . data , PAGE_SIZE , 0 , 0 ,
2014-12-12 22:46:38 +03:00
" attempting extend a PCR value " ) ;
2017-01-30 12:59:41 +03:00
tpm_buf_destroy ( & buf ) ;
2014-12-12 22:46:38 +03:00
return rc ;
}
2017-01-30 12:59:41 +03:00
2014-12-12 22:46:38 +03:00
# define TPM2_GETRANDOM_IN_SIZE \
( sizeof ( struct tpm_input_header ) + \
sizeof ( struct tpm2_get_random_in ) )
static const struct tpm_input_header tpm2_getrandom_header = {
. tag = cpu_to_be16 ( TPM2_ST_NO_SESSIONS ) ,
. length = cpu_to_be32 ( TPM2_GETRANDOM_IN_SIZE ) ,
. ordinal = cpu_to_be32 ( TPM2_CC_GET_RANDOM )
} ;
/**
* tpm2_get_random ( ) - get random bytes from the TPM RNG
2016-11-23 13:04:12 +03:00
*
2014-12-12 22:46:38 +03:00
* @ chip : TPM chip to use
* @ out : destination buffer for the random bytes
* @ max : the max number of bytes to write to @ out
*
2016-11-23 13:04:12 +03:00
* Return :
* Size of the output buffer , or - EIO on error .
2014-12-12 22:46:38 +03:00
*/
int tpm2_get_random ( struct tpm_chip * chip , u8 * out , size_t max )
{
struct tpm2_cmd cmd ;
2017-01-19 15:19:12 +03:00
u32 recd , rlength ;
2014-12-12 22:46:38 +03:00
u32 num_bytes ;
int err ;
int total = 0 ;
int retries = 5 ;
u8 * dest = out ;
num_bytes = min_t ( u32 , max , sizeof ( cmd . params . getrandom_out . buffer ) ) ;
if ( ! out | | ! num_bytes | |
max > sizeof ( cmd . params . getrandom_out . buffer ) )
return - EINVAL ;
do {
cmd . header . in = tpm2_getrandom_header ;
cmd . params . getrandom_in . size = cpu_to_be16 ( num_bytes ) ;
2017-01-06 15:03:45 +03:00
err = tpm_transmit_cmd ( chip , NULL , & cmd , sizeof ( cmd ) ,
2017-01-19 15:19:12 +03:00
offsetof ( struct tpm2_get_random_out ,
buffer ) ,
0 , " attempting get random " ) ;
2014-12-12 22:46:38 +03:00
if ( err )
break ;
recd = min_t ( u32 , be16_to_cpu ( cmd . params . getrandom_out . size ) ,
num_bytes ) ;
2017-01-19 15:19:12 +03:00
rlength = be32_to_cpu ( cmd . header . out . length ) ;
if ( rlength < offsetof ( struct tpm2_get_random_out , buffer ) +
recd )
return - EFAULT ;
2014-12-12 22:46:38 +03:00
memcpy ( dest , cmd . params . getrandom_out . buffer , recd ) ;
dest + = recd ;
total + = recd ;
num_bytes - = recd ;
} while ( retries - - & & total < max ) ;
return total ? total : - EIO ;
}
# define TPM2_GET_TPM_PT_IN_SIZE \
( sizeof ( struct tpm_input_header ) + \
sizeof ( struct tpm2_get_tpm_pt_in ) )
2017-01-19 15:19:12 +03:00
# define TPM2_GET_TPM_PT_OUT_BODY_SIZE \
sizeof ( struct tpm2_get_tpm_pt_out )
2014-12-12 22:46:38 +03:00
static const struct tpm_input_header tpm2_get_tpm_pt_header = {
. tag = cpu_to_be16 ( TPM2_ST_NO_SESSIONS ) ,
. length = cpu_to_be32 ( TPM2_GET_TPM_PT_IN_SIZE ) ,
. ordinal = cpu_to_be32 ( TPM2_CC_GET_CAPABILITY )
} ;
2016-11-26 14:39:35 +03:00
/**
* tpm2_flush_context_cmd ( ) - execute a TPM2_FlushContext command
* @ chip : TPM chip to use
* @ payload : the key data in clear and encrypted form
* @ options : authentication values and other options
*
* Return : same as with tpm_transmit_cmd
*/
void tpm2_flush_context_cmd ( struct tpm_chip * chip , u32 handle ,
unsigned int flags )
{
struct tpm_buf buf ;
int rc ;
rc = tpm_buf_init ( & buf , TPM2_ST_NO_SESSIONS , TPM2_CC_FLUSH_CONTEXT ) ;
if ( rc ) {
dev_warn ( & chip - > dev , " 0x%08x was not flushed, out of memory \n " ,
handle ) ;
return ;
}
tpm_buf_append_u32 ( & buf , handle ) ;
2017-01-06 15:03:45 +03:00
( void ) tpm_transmit_cmd ( chip , NULL , buf . data , PAGE_SIZE , 0 , flags ,
2016-11-26 14:39:35 +03:00
" flushing context " ) ;
tpm_buf_destroy ( & buf ) ;
}
2015-05-30 08:09:04 +03:00
/**
2016-11-23 13:04:12 +03:00
* tpm_buf_append_auth ( ) - append TPMS_AUTH_COMMAND to the buffer .
*
* @ buf : an allocated tpm_buf instance
* @ session_handle : session handle
* @ nonce : the session nonce , may be NULL if not used
* @ nonce_len : the session nonce length , may be 0 if not used
* @ attributes : the session attributes
* @ hmac : the session HMAC or password , may be NULL if not used
* @ hmac_len : the session HMAC or password length , maybe 0 if not used
2015-05-30 08:09:04 +03:00
*/
static void tpm2_buf_append_auth ( struct tpm_buf * buf , u32 session_handle ,
const u8 * nonce , u16 nonce_len ,
u8 attributes ,
const u8 * hmac , u16 hmac_len )
{
tpm_buf_append_u32 ( buf , 9 + nonce_len + hmac_len ) ;
tpm_buf_append_u32 ( buf , session_handle ) ;
tpm_buf_append_u16 ( buf , nonce_len ) ;
if ( nonce & & nonce_len )
tpm_buf_append ( buf , nonce , nonce_len ) ;
tpm_buf_append_u8 ( buf , attributes ) ;
tpm_buf_append_u16 ( buf , hmac_len ) ;
if ( hmac & & hmac_len )
tpm_buf_append ( buf , hmac , hmac_len ) ;
}
/**
2016-08-16 22:00:38 +03:00
* tpm2_seal_trusted ( ) - seal the payload of a trusted key
2016-11-23 13:04:12 +03:00
*
* @ chip : TPM chip to use
2015-05-30 08:09:04 +03:00
* @ payload : the key data in clear and encrypted form
2016-08-16 22:00:38 +03:00
* @ options : authentication values and other options
2015-05-30 08:09:04 +03:00
*
2016-08-16 22:00:38 +03:00
* Return : < 0 on error and 0 on success .
2015-05-30 08:09:04 +03:00
*/
int tpm2_seal_trusted ( struct tpm_chip * chip ,
struct trusted_key_payload * payload ,
struct trusted_key_options * options )
{
unsigned int blob_len ;
struct tpm_buf buf ;
2017-01-19 15:19:12 +03:00
u32 hash , rlength ;
2015-11-05 22:43:06 +03:00
int i ;
2015-05-30 08:09:04 +03:00
int rc ;
2015-11-05 22:43:06 +03:00
for ( i = 0 ; i < ARRAY_SIZE ( tpm2_hash_map ) ; i + + ) {
if ( options - > hash = = tpm2_hash_map [ i ] . crypto_id ) {
hash = tpm2_hash_map [ i ] . tpm_id ;
break ;
}
}
if ( i = = ARRAY_SIZE ( tpm2_hash_map ) )
return - EINVAL ;
2015-05-30 08:09:04 +03:00
rc = tpm_buf_init ( & buf , TPM2_ST_SESSIONS , TPM2_CC_CREATE ) ;
if ( rc )
return rc ;
tpm_buf_append_u32 ( & buf , options - > keyhandle ) ;
tpm2_buf_append_auth ( & buf , TPM2_RS_PW ,
NULL /* nonce */ , 0 ,
0 /* session_attributes */ ,
options - > keyauth /* hmac */ ,
TPM_DIGEST_SIZE ) ;
/* sensitive */
2015-10-30 15:57:02 +03:00
tpm_buf_append_u16 ( & buf , 4 + TPM_DIGEST_SIZE + payload - > key_len + 1 ) ;
2015-05-30 08:09:04 +03:00
tpm_buf_append_u16 ( & buf , TPM_DIGEST_SIZE ) ;
tpm_buf_append ( & buf , options - > blobauth , TPM_DIGEST_SIZE ) ;
2015-10-30 15:57:02 +03:00
tpm_buf_append_u16 ( & buf , payload - > key_len + 1 ) ;
2015-05-30 08:09:04 +03:00
tpm_buf_append ( & buf , payload - > key , payload - > key_len ) ;
2015-10-30 15:57:02 +03:00
tpm_buf_append_u8 ( & buf , payload - > migratable ) ;
2015-05-30 08:09:04 +03:00
/* public */
2016-01-06 17:43:30 +03:00
tpm_buf_append_u16 ( & buf , 14 + options - > policydigest_len ) ;
2015-05-30 08:09:04 +03:00
tpm_buf_append_u16 ( & buf , TPM2_ALG_KEYEDHASH ) ;
2015-11-05 22:43:06 +03:00
tpm_buf_append_u16 ( & buf , hash ) ;
2015-10-31 18:53:44 +03:00
/* policy */
2016-01-06 17:43:30 +03:00
if ( options - > policydigest_len ) {
2015-10-31 18:53:44 +03:00
tpm_buf_append_u32 ( & buf , 0 ) ;
2016-01-06 17:43:30 +03:00
tpm_buf_append_u16 ( & buf , options - > policydigest_len ) ;
2015-10-31 18:53:44 +03:00
tpm_buf_append ( & buf , options - > policydigest ,
2016-01-06 17:43:30 +03:00
options - > policydigest_len ) ;
2015-10-31 18:53:44 +03:00
} else {
2016-02-13 12:51:23 +03:00
tpm_buf_append_u32 ( & buf , TPM2_OA_USER_WITH_AUTH ) ;
2015-10-31 18:53:44 +03:00
tpm_buf_append_u16 ( & buf , 0 ) ;
}
/* public parameters */
2015-05-30 08:09:04 +03:00
tpm_buf_append_u16 ( & buf , TPM2_ALG_NULL ) ;
tpm_buf_append_u16 ( & buf , 0 ) ;
/* outside info */
tpm_buf_append_u16 ( & buf , 0 ) ;
/* creation PCR */
tpm_buf_append_u32 ( & buf , 0 ) ;
if ( buf . flags & TPM_BUF_OVERFLOW ) {
rc = - E2BIG ;
goto out ;
}
2017-01-06 15:03:45 +03:00
rc = tpm_transmit_cmd ( chip , NULL , buf . data , PAGE_SIZE , 4 , 0 ,
2017-01-19 15:19:12 +03:00
" sealing data " ) ;
2015-05-30 08:09:04 +03:00
if ( rc )
goto out ;
blob_len = be32_to_cpup ( ( __be32 * ) & buf . data [ TPM_HEADER_SIZE ] ) ;
if ( blob_len > MAX_BLOB_SIZE ) {
rc = - E2BIG ;
goto out ;
}
2017-01-19 15:19:12 +03:00
rlength = be32_to_cpu ( ( ( struct tpm2_cmd * ) & buf ) - > header . out . length ) ;
if ( rlength < TPM_HEADER_SIZE + 4 + blob_len ) {
rc = - EFAULT ;
goto out ;
}
2015-05-30 08:09:04 +03:00
memcpy ( payload - > blob , & buf . data [ TPM_HEADER_SIZE + 4 ] , blob_len ) ;
payload - > blob_len = blob_len ;
out :
tpm_buf_destroy ( & buf ) ;
2015-11-05 22:43:06 +03:00
if ( rc > 0 ) {
2017-01-26 00:00:22 +03:00
if ( tpm2_rc_value ( rc ) = = TPM2_RC_HASH )
2015-11-05 22:43:06 +03:00
rc = - EINVAL ;
else
rc = - EPERM ;
}
2015-05-30 08:09:04 +03:00
return rc ;
}
2016-08-16 22:00:38 +03:00
/**
* tpm2_load_cmd ( ) - execute a TPM2_Load command
2016-11-23 13:04:12 +03:00
*
* @ chip : TPM chip to use
2016-08-16 22:00:38 +03:00
* @ payload : the key data in clear and encrypted form
* @ options : authentication values and other options
2016-11-23 13:04:12 +03:00
* @ blob_handle : returned blob handle
* @ flags : tpm transmit flags
2016-08-16 22:00:38 +03:00
*
2016-11-23 13:04:12 +03:00
* Return : 0 on success .
* - E2BIG on wrong payload size .
* - EPERM on tpm error status .
* < 0 error from tpm_transmit_cmd .
2016-08-16 22:00:38 +03:00
*/
static int tpm2_load_cmd ( struct tpm_chip * chip ,
struct trusted_key_payload * payload ,
struct trusted_key_options * options ,
u32 * blob_handle , unsigned int flags )
2015-05-30 08:09:04 +03:00
{
struct tpm_buf buf ;
unsigned int private_len ;
unsigned int public_len ;
unsigned int blob_len ;
int rc ;
private_len = be16_to_cpup ( ( __be16 * ) & payload - > blob [ 0 ] ) ;
if ( private_len > ( payload - > blob_len - 2 ) )
return - E2BIG ;
public_len = be16_to_cpup ( ( __be16 * ) & payload - > blob [ 2 + private_len ] ) ;
blob_len = private_len + public_len + 4 ;
if ( blob_len > payload - > blob_len )
return - E2BIG ;
rc = tpm_buf_init ( & buf , TPM2_ST_SESSIONS , TPM2_CC_LOAD ) ;
if ( rc )
return rc ;
tpm_buf_append_u32 ( & buf , options - > keyhandle ) ;
tpm2_buf_append_auth ( & buf , TPM2_RS_PW ,
NULL /* nonce */ , 0 ,
0 /* session_attributes */ ,
options - > keyauth /* hmac */ ,
TPM_DIGEST_SIZE ) ;
tpm_buf_append ( & buf , payload - > blob , blob_len ) ;
if ( buf . flags & TPM_BUF_OVERFLOW ) {
rc = - E2BIG ;
goto out ;
}
2017-01-06 15:03:45 +03:00
rc = tpm_transmit_cmd ( chip , NULL , buf . data , PAGE_SIZE , 4 , flags ,
2017-01-19 15:19:12 +03:00
" loading blob " ) ;
2015-05-30 08:09:04 +03:00
if ( ! rc )
* blob_handle = be32_to_cpup (
( __be32 * ) & buf . data [ TPM_HEADER_SIZE ] ) ;
out :
tpm_buf_destroy ( & buf ) ;
if ( rc > 0 )
rc = - EPERM ;
return rc ;
}
2016-08-16 22:00:38 +03:00
/**
* tpm2_unseal_cmd ( ) - execute a TPM2_Unload command
2016-11-23 13:04:12 +03:00
*
* @ chip : TPM chip to use
2016-08-16 22:00:38 +03:00
* @ payload : the key data in clear and encrypted form
* @ options : authentication values and other options
2016-11-23 13:04:12 +03:00
* @ blob_handle : blob handle
* @ flags : tpm_transmit_cmd flags
2016-08-16 22:00:38 +03:00
*
2016-11-23 13:04:12 +03:00
* Return : 0 on success
* - EPERM on tpm error status
* < 0 error from tpm_transmit_cmd
2016-08-16 22:00:38 +03:00
*/
static int tpm2_unseal_cmd ( struct tpm_chip * chip ,
struct trusted_key_payload * payload ,
struct trusted_key_options * options ,
u32 blob_handle , unsigned int flags )
2015-05-30 08:09:04 +03:00
{
struct tpm_buf buf ;
2015-10-30 15:57:02 +03:00
u16 data_len ;
u8 * data ;
2015-05-30 08:09:04 +03:00
int rc ;
2017-01-19 15:19:12 +03:00
u32 rlength ;
2015-05-30 08:09:04 +03:00
rc = tpm_buf_init ( & buf , TPM2_ST_SESSIONS , TPM2_CC_UNSEAL ) ;
if ( rc )
return rc ;
tpm_buf_append_u32 ( & buf , blob_handle ) ;
2015-10-31 18:53:44 +03:00
tpm2_buf_append_auth ( & buf ,
options - > policyhandle ?
options - > policyhandle : TPM2_RS_PW ,
2015-05-30 08:09:04 +03:00
NULL /* nonce */ , 0 ,
2016-02-13 12:51:23 +03:00
TPM2_SA_CONTINUE_SESSION ,
2015-05-30 08:09:04 +03:00
options - > blobauth /* hmac */ ,
TPM_DIGEST_SIZE ) ;
2017-01-06 15:03:45 +03:00
rc = tpm_transmit_cmd ( chip , NULL , buf . data , PAGE_SIZE , 6 , flags ,
2017-01-19 15:19:12 +03:00
" unsealing " ) ;
2015-05-30 08:09:04 +03:00
if ( rc > 0 )
rc = - EPERM ;
if ( ! rc ) {
2015-10-30 15:57:02 +03:00
data_len = be16_to_cpup (
2015-05-30 08:09:04 +03:00
( __be16 * ) & buf . data [ TPM_HEADER_SIZE + 4 ] ) ;
2017-01-19 15:19:12 +03:00
rlength = be32_to_cpu ( ( ( struct tpm2_cmd * ) & buf )
- > header . out . length ) ;
if ( rlength < TPM_HEADER_SIZE + 6 + data_len ) {
rc = - EFAULT ;
goto out ;
}
2015-10-30 15:57:02 +03:00
data = & buf . data [ TPM_HEADER_SIZE + 6 ] ;
2015-05-30 08:09:04 +03:00
2015-10-30 15:57:02 +03:00
memcpy ( payload - > key , data , data_len - 1 ) ;
payload - > key_len = data_len - 1 ;
payload - > migratable = data [ data_len - 1 ] ;
2015-05-30 08:09:04 +03:00
}
2017-01-19 15:19:12 +03:00
out :
2015-05-30 08:09:04 +03:00
tpm_buf_destroy ( & buf ) ;
return rc ;
}
/**
2016-11-06 12:02:45 +03:00
* tpm2_unseal_trusted ( ) - unseal the payload of a trusted key
2016-11-23 13:04:12 +03:00
*
* @ chip : TPM chip to use
2015-05-30 08:09:04 +03:00
* @ payload : the key data in clear and encrypted form
2016-08-16 22:00:38 +03:00
* @ options : authentication values and other options
2015-05-30 08:09:04 +03:00
*
2016-11-23 13:04:12 +03:00
* Return : Same as with tpm_transmit_cmd .
2015-05-30 08:09:04 +03:00
*/
int tpm2_unseal_trusted ( struct tpm_chip * chip ,
struct trusted_key_payload * payload ,
struct trusted_key_options * options )
{
u32 blob_handle ;
int rc ;
2016-08-16 22:00:38 +03:00
mutex_lock ( & chip - > tpm_mutex ) ;
rc = tpm2_load_cmd ( chip , payload , options , & blob_handle ,
TPM_TRANSMIT_UNLOCKED ) ;
2015-05-30 08:09:04 +03:00
if ( rc )
2016-08-16 22:00:38 +03:00
goto out ;
2015-05-30 08:09:04 +03:00
2016-08-16 22:00:38 +03:00
rc = tpm2_unseal_cmd ( chip , payload , options , blob_handle ,
TPM_TRANSMIT_UNLOCKED ) ;
tpm2_flush_context_cmd ( chip , blob_handle , TPM_TRANSMIT_UNLOCKED ) ;
out :
mutex_unlock ( & chip - > tpm_mutex ) ;
2015-05-30 08:09:04 +03:00
return rc ;
}
2014-12-12 22:46:38 +03:00
/**
* tpm2_get_tpm_pt ( ) - get value of a TPM_CAP_TPM_PROPERTIES type property
* @ chip : TPM chip to use .
* @ property_id : property ID .
* @ value : output variable .
* @ desc : passed to tpm_transmit_cmd ( )
*
2016-11-23 13:04:12 +03:00
* Return : Same as with tpm_transmit_cmd .
2014-12-12 22:46:38 +03:00
*/
ssize_t tpm2_get_tpm_pt ( struct tpm_chip * chip , u32 property_id , u32 * value ,
const char * desc )
{
struct tpm2_cmd cmd ;
int rc ;
cmd . header . in = tpm2_get_tpm_pt_header ;
cmd . params . get_tpm_pt_in . cap_id = cpu_to_be32 ( TPM2_CAP_TPM_PROPERTIES ) ;
cmd . params . get_tpm_pt_in . property_id = cpu_to_be32 ( property_id ) ;
cmd . params . get_tpm_pt_in . property_cnt = cpu_to_be32 ( 1 ) ;
2017-01-06 15:03:45 +03:00
rc = tpm_transmit_cmd ( chip , NULL , & cmd , sizeof ( cmd ) ,
2017-01-19 15:19:12 +03:00
TPM2_GET_TPM_PT_OUT_BODY_SIZE , 0 , desc ) ;
2014-12-12 22:46:38 +03:00
if ( ! rc )
2016-07-15 04:07:18 +03:00
* value = be32_to_cpu ( cmd . params . get_tpm_pt_out . value ) ;
2014-12-12 22:46:38 +03:00
return rc ;
}
2016-06-12 16:42:09 +03:00
EXPORT_SYMBOL_GPL ( tpm2_get_tpm_pt ) ;
2014-12-12 22:46:38 +03:00
# define TPM2_STARTUP_IN_SIZE \
( sizeof ( struct tpm_input_header ) + \
sizeof ( struct tpm2_startup_in ) )
static const struct tpm_input_header tpm2_startup_header = {
. tag = cpu_to_be16 ( TPM2_ST_NO_SESSIONS ) ,
. length = cpu_to_be32 ( TPM2_STARTUP_IN_SIZE ) ,
. ordinal = cpu_to_be32 ( TPM2_CC_STARTUP )
} ;
/**
* tpm2_startup ( ) - send startup command to the TPM chip
2016-11-23 13:04:12 +03:00
*
2014-12-12 22:46:38 +03:00
* @ chip : TPM chip to use .
2016-11-23 13:04:12 +03:00
* @ startup_type : startup type . The value is either
2014-12-12 22:46:38 +03:00
* TPM_SU_CLEAR or TPM_SU_STATE .
*
2016-11-23 13:04:12 +03:00
* Return : Same as with tpm_transmit_cmd .
2014-12-12 22:46:38 +03:00
*/
2016-07-12 20:41:49 +03:00
static int tpm2_startup ( struct tpm_chip * chip , u16 startup_type )
2014-12-12 22:46:38 +03:00
{
struct tpm2_cmd cmd ;
cmd . header . in = tpm2_startup_header ;
cmd . params . startup_in . startup_type = cpu_to_be16 ( startup_type ) ;
2017-01-06 15:03:45 +03:00
return tpm_transmit_cmd ( chip , NULL , & cmd , sizeof ( cmd ) , 0 , 0 ,
2014-12-12 22:46:38 +03:00
" attempting to start the TPM " ) ;
}
# define TPM2_SHUTDOWN_IN_SIZE \
( sizeof ( struct tpm_input_header ) + \
sizeof ( struct tpm2_startup_in ) )
static const struct tpm_input_header tpm2_shutdown_header = {
. tag = cpu_to_be16 ( TPM2_ST_NO_SESSIONS ) ,
. length = cpu_to_be32 ( TPM2_SHUTDOWN_IN_SIZE ) ,
. ordinal = cpu_to_be32 ( TPM2_CC_SHUTDOWN )
} ;
/**
* tpm2_shutdown ( ) - send shutdown command to the TPM chip
2016-11-23 13:04:12 +03:00
*
2014-12-12 22:46:38 +03:00
* @ chip : TPM chip to use .
2016-11-23 13:04:12 +03:00
* @ shutdown_type : shutdown type . The value is either
2014-12-12 22:46:38 +03:00
* TPM_SU_CLEAR or TPM_SU_STATE .
*/
2015-01-29 08:43:47 +03:00
void tpm2_shutdown ( struct tpm_chip * chip , u16 shutdown_type )
2014-12-12 22:46:38 +03:00
{
struct tpm2_cmd cmd ;
2015-01-29 08:43:47 +03:00
int rc ;
2014-12-12 22:46:38 +03:00
cmd . header . in = tpm2_shutdown_header ;
cmd . params . startup_in . startup_type = cpu_to_be16 ( shutdown_type ) ;
2015-01-29 08:43:47 +03:00
2017-01-06 15:03:45 +03:00
rc = tpm_transmit_cmd ( chip , NULL , & cmd , sizeof ( cmd ) , 0 , 0 ,
2017-01-19 15:19:12 +03:00
" stopping the TPM " ) ;
2015-01-29 08:43:47 +03:00
/* In places where shutdown command is sent there's no much we can do
* except print the error code on a system failure .
*/
if ( rc < 0 )
2016-02-29 20:29:47 +03:00
dev_warn ( & chip - > dev , " transmit returned %d while stopping the TPM " ,
2015-01-29 08:43:47 +03:00
rc ) ;
2014-12-12 22:46:38 +03:00
}
/*
* tpm2_calc_ordinal_duration ( ) - maximum duration for a command
2016-11-23 13:04:12 +03:00
*
2014-12-12 22:46:38 +03:00
* @ chip : TPM chip to use .
* @ ordinal : command code number .
*
2016-11-23 13:04:12 +03:00
* Return : maximum duration for a command
2014-12-12 22:46:38 +03:00
*/
unsigned long tpm2_calc_ordinal_duration ( struct tpm_chip * chip , u32 ordinal )
{
int index = TPM_UNDEFINED ;
int duration = 0 ;
if ( ordinal > = TPM2_CC_FIRST & & ordinal < = TPM2_CC_LAST )
index = tpm2_ordinal_duration [ ordinal - TPM2_CC_FIRST ] ;
if ( index ! = TPM_UNDEFINED )
2016-03-31 23:56:59 +03:00
duration = chip - > duration [ index ] ;
2014-12-12 22:46:38 +03:00
if ( duration < = 0 )
duration = 2 * 60 * HZ ;
return duration ;
}
EXPORT_SYMBOL_GPL ( tpm2_calc_ordinal_duration ) ;
# define TPM2_SELF_TEST_IN_SIZE \
( sizeof ( struct tpm_input_header ) + \
sizeof ( struct tpm2_self_test_in ) )
static const struct tpm_input_header tpm2_selftest_header = {
. tag = cpu_to_be16 ( TPM2_ST_NO_SESSIONS ) ,
. length = cpu_to_be32 ( TPM2_SELF_TEST_IN_SIZE ) ,
. ordinal = cpu_to_be32 ( TPM2_CC_SELF_TEST )
} ;
/**
* tpm2_continue_selftest ( ) - start a self test
2016-11-23 13:04:12 +03:00
*
2014-12-12 22:46:38 +03:00
* @ chip : TPM chip to use
* @ full : test all commands instead of testing only those that were not
* previously tested .
*
2016-11-23 13:04:12 +03:00
* Return : Same as with tpm_transmit_cmd with exception of RC_TESTING .
2014-12-12 22:46:38 +03:00
*/
static int tpm2_start_selftest ( struct tpm_chip * chip , bool full )
{
int rc ;
struct tpm2_cmd cmd ;
cmd . header . in = tpm2_selftest_header ;
cmd . params . selftest_in . full_test = full ;
2017-01-06 15:03:45 +03:00
rc = tpm_transmit_cmd ( chip , NULL , & cmd , TPM2_SELF_TEST_IN_SIZE , 0 , 0 ,
2014-12-12 22:46:38 +03:00
" continue selftest " ) ;
/* At least some prototype chips seem to give RC_TESTING error
* immediately . This is a workaround for that .
*/
if ( rc = = TPM2_RC_TESTING ) {
2016-02-29 20:29:47 +03:00
dev_warn ( & chip - > dev , " Got RC_TESTING, ignoring \n " ) ;
2014-12-12 22:46:38 +03:00
rc = 0 ;
}
return rc ;
}
/**
* tpm2_do_selftest ( ) - run a full self test
2016-11-23 13:04:12 +03:00
*
2014-12-12 22:46:38 +03:00
* @ chip : TPM chip to use
*
2016-11-23 13:04:12 +03:00
* Return : Same as with tpm_transmit_cmd .
*
2014-12-12 22:46:38 +03:00
* During the self test TPM2 commands return with the error code RC_TESTING .
* Waiting is done by issuing PCR read until it executes successfully .
*/
2016-07-12 20:41:49 +03:00
static int tpm2_do_selftest ( struct tpm_chip * chip )
2014-12-12 22:46:38 +03:00
{
int rc ;
unsigned int loops ;
unsigned int delay_msec = 100 ;
unsigned long duration ;
struct tpm2_cmd cmd ;
int i ;
duration = tpm2_calc_ordinal_duration ( chip , TPM2_CC_SELF_TEST ) ;
loops = jiffies_to_msecs ( duration ) / delay_msec ;
rc = tpm2_start_selftest ( chip , true ) ;
if ( rc )
return rc ;
for ( i = 0 ; i < loops ; i + + ) {
/* Attempt to read a PCR value */
cmd . header . in = tpm2_pcrread_header ;
cmd . params . pcrread_in . pcr_selects_cnt = cpu_to_be32 ( 1 ) ;
cmd . params . pcrread_in . hash_alg = cpu_to_be16 ( TPM2_ALG_SHA1 ) ;
cmd . params . pcrread_in . pcr_select_size = TPM2_PCR_SELECT_MIN ;
cmd . params . pcrread_in . pcr_select [ 0 ] = 0x01 ;
cmd . params . pcrread_in . pcr_select [ 1 ] = 0x00 ;
cmd . params . pcrread_in . pcr_select [ 2 ] = 0x00 ;
2017-01-06 15:03:45 +03:00
rc = tpm_transmit_cmd ( chip , NULL , & cmd , sizeof ( cmd ) , 0 , 0 ,
NULL ) ;
2014-12-12 22:46:38 +03:00
if ( rc < 0 )
break ;
rc = be32_to_cpu ( cmd . header . out . return_code ) ;
if ( rc ! = TPM2_RC_TESTING )
break ;
msleep ( delay_msec ) ;
}
return rc ;
}
2015-02-04 17:21:09 +03:00
/**
* tpm2_probe ( ) - probe TPM 2.0
* @ chip : TPM chip to use
*
2016-11-23 13:04:12 +03:00
* Return : < 0 error and 0 on success .
*
2015-02-04 17:21:09 +03:00
* Send idempotent TPM 2.0 command and see whether TPM 2.0 chip replied based on
* the reply tag .
*/
int tpm2_probe ( struct tpm_chip * chip )
{
struct tpm2_cmd cmd ;
int rc ;
cmd . header . in = tpm2_get_tpm_pt_header ;
cmd . params . get_tpm_pt_in . cap_id = cpu_to_be32 ( TPM2_CAP_TPM_PROPERTIES ) ;
cmd . params . get_tpm_pt_in . property_id = cpu_to_be32 ( 0x100 ) ;
cmd . params . get_tpm_pt_in . property_cnt = cpu_to_be32 ( 1 ) ;
2017-01-06 15:03:45 +03:00
rc = tpm_transmit_cmd ( chip , NULL , & cmd , sizeof ( cmd ) , 0 , 0 , NULL ) ;
2015-02-04 17:21:09 +03:00
if ( rc < 0 )
return rc ;
if ( be16_to_cpu ( cmd . header . out . tag ) = = TPM2_ST_NO_SESSIONS )
chip - > flags | = TPM_CHIP_FLAG_TPM2 ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( tpm2_probe ) ;
2016-07-12 20:41:49 +03:00
2017-01-30 12:59:40 +03:00
struct tpm2_pcr_selection {
__be16 hash_alg ;
u8 size_of_select ;
u8 pcr_select [ 3 ] ;
} __packed ;
2017-02-15 21:02:28 +03:00
static ssize_t tpm2_get_pcr_allocation ( struct tpm_chip * chip )
2017-01-30 12:59:40 +03:00
{
struct tpm2_pcr_selection pcr_selection ;
struct tpm_buf buf ;
void * marker ;
void * end ;
void * pcr_select_offset ;
unsigned int count ;
u32 sizeof_pcr_selection ;
u32 rsp_len ;
int rc ;
int i = 0 ;
rc = tpm_buf_init ( & buf , TPM2_ST_NO_SESSIONS , TPM2_CC_GET_CAPABILITY ) ;
if ( rc )
return rc ;
tpm_buf_append_u32 ( & buf , TPM2_CAP_PCRS ) ;
tpm_buf_append_u32 ( & buf , 0 ) ;
tpm_buf_append_u32 ( & buf , 1 ) ;
2017-01-06 15:03:45 +03:00
rc = tpm_transmit_cmd ( chip , NULL , buf . data , PAGE_SIZE , 9 , 0 ,
2017-01-30 12:59:40 +03:00
" get tpm pcr allocation " ) ;
if ( rc )
goto out ;
count = be32_to_cpup (
( __be32 * ) & buf . data [ TPM_HEADER_SIZE + 5 ] ) ;
if ( count > ARRAY_SIZE ( chip - > active_banks ) ) {
rc = - ENODEV ;
goto out ;
}
marker = & buf . data [ TPM_HEADER_SIZE + 9 ] ;
rsp_len = be32_to_cpup ( ( __be32 * ) & buf . data [ 2 ] ) ;
end = & buf . data [ rsp_len ] ;
for ( i = 0 ; i < count ; i + + ) {
pcr_select_offset = marker +
offsetof ( struct tpm2_pcr_selection , size_of_select ) ;
if ( pcr_select_offset > = end ) {
rc = - EFAULT ;
break ;
}
memcpy ( & pcr_selection , marker , sizeof ( pcr_selection ) ) ;
chip - > active_banks [ i ] = be16_to_cpu ( pcr_selection . hash_alg ) ;
sizeof_pcr_selection = sizeof ( pcr_selection . hash_alg ) +
sizeof ( pcr_selection . size_of_select ) +
pcr_selection . size_of_select ;
marker = marker + sizeof_pcr_selection ;
}
out :
if ( i < ARRAY_SIZE ( chip - > active_banks ) )
chip - > active_banks [ i ] = TPM2_ALG_ERROR ;
tpm_buf_destroy ( & buf ) ;
return rc ;
}
2017-02-15 21:02:28 +03:00
2016-11-11 07:42:07 +03:00
static int tpm2_get_cc_attrs_tbl ( struct tpm_chip * chip )
{
struct tpm_buf buf ;
u32 nr_commands ;
u32 * attrs ;
u32 cc ;
int i ;
int rc ;
rc = tpm2_get_tpm_pt ( chip , TPM_PT_TOTAL_COMMANDS , & nr_commands , NULL ) ;
if ( rc )
goto out ;
if ( nr_commands > 0xFFFFF ) {
rc = - EFAULT ;
goto out ;
}
chip - > cc_attrs_tbl = devm_kzalloc ( & chip - > dev , 4 * nr_commands ,
GFP_KERNEL ) ;
rc = tpm_buf_init ( & buf , TPM2_ST_NO_SESSIONS , TPM2_CC_GET_CAPABILITY ) ;
if ( rc )
goto out ;
tpm_buf_append_u32 ( & buf , TPM2_CAP_COMMANDS ) ;
tpm_buf_append_u32 ( & buf , TPM2_CC_FIRST ) ;
tpm_buf_append_u32 ( & buf , nr_commands ) ;
2017-01-06 15:03:45 +03:00
rc = tpm_transmit_cmd ( chip , NULL , buf . data , PAGE_SIZE ,
9 + 4 * nr_commands , 0 , NULL ) ;
2016-11-11 07:42:07 +03:00
if ( rc ) {
tpm_buf_destroy ( & buf ) ;
goto out ;
}
if ( nr_commands ! =
be32_to_cpup ( ( __be32 * ) & buf . data [ TPM_HEADER_SIZE + 5 ] ) ) {
tpm_buf_destroy ( & buf ) ;
goto out ;
}
chip - > nr_commands = nr_commands ;
attrs = ( u32 * ) & buf . data [ TPM_HEADER_SIZE + 9 ] ;
for ( i = 0 ; i < nr_commands ; i + + , attrs + + ) {
chip - > cc_attrs_tbl [ i ] = be32_to_cpup ( attrs ) ;
cc = chip - > cc_attrs_tbl [ i ] & 0xFFFF ;
if ( cc = = TPM2_CC_CONTEXT_SAVE | | cc = = TPM2_CC_FLUSH_CONTEXT ) {
chip - > cc_attrs_tbl [ i ] & =
~ ( GENMASK ( 2 , 0 ) < < TPM2_CC_ATTR_CHANDLES ) ;
chip - > cc_attrs_tbl [ i ] | = 1 < < TPM2_CC_ATTR_CHANDLES ;
}
}
tpm_buf_destroy ( & buf ) ;
out :
if ( rc > 0 )
rc = - ENODEV ;
return rc ;
}
2017-02-15 21:02:28 +03:00
/**
* tpm2_auto_startup - Perform the standard automatic TPM initialization
* sequence
* @ chip : TPM chip to use
*
2016-11-11 07:42:07 +03:00
* Returns 0 on success , < 0 in case of fatal error .
2017-02-15 21:02:28 +03:00
*/
int tpm2_auto_startup ( struct tpm_chip * chip )
{
int rc ;
rc = tpm_get_timeouts ( chip ) ;
if ( rc )
goto out ;
rc = tpm2_do_selftest ( chip ) ;
if ( rc ! = 0 & & rc ! = TPM2_RC_INITIALIZE ) {
dev_err ( & chip - > dev , " TPM self test failed \n " ) ;
goto out ;
}
if ( rc = = TPM2_RC_INITIALIZE ) {
rc = tpm2_startup ( chip , TPM2_SU_CLEAR ) ;
if ( rc )
goto out ;
rc = tpm2_do_selftest ( chip ) ;
if ( rc ) {
dev_err ( & chip - > dev , " TPM self test failed \n " ) ;
goto out ;
}
}
rc = tpm2_get_pcr_allocation ( chip ) ;
2016-11-11 07:42:07 +03:00
if ( rc )
goto out ;
rc = tpm2_get_cc_attrs_tbl ( chip ) ;
2017-02-15 21:02:28 +03:00
out :
if ( rc > 0 )
rc = - ENODEV ;
return rc ;
}
2016-11-11 07:42:07 +03:00
int tpm2_find_cc ( struct tpm_chip * chip , u32 cc )
{
int i ;
for ( i = 0 ; i < chip - > nr_commands ; i + + )
if ( cc = = ( chip - > cc_attrs_tbl [ i ] & GENMASK ( 15 , 0 ) ) )
return i ;
return - 1 ;
}