#CHIPSEC: Platform Security Assessment Framework
#Copyright (c) 2010-2016, Intel Corporation
# 
#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.
#
#This program is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#GNU General Public License for more details.
#
#You should have received a copy of the GNU General Public License
#along with this program; if not, write to the Free Software
#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#
#Contact information:
#chipsec@intel.com
#



"""
Definition for TPMv1.2 commands to use with TPM HAL

TCG PC Client TPM Specification
TCG TPM v1.2 Specification
"""

import struct
from chipsec.logger import *

COMMAND_FORMAT = "=HIIIII"

TPM_TAG_RQU_COMMAND = 0xc100
TPM_TAG_RQU_AUTH1_COMMAND = 0xc200
TPM_TAG_RQU_AUTH2_COMMAND = 0xC300
TPM_TAG_RSP_COMMAND = 0xC400
TPM_TAG_RSP_AUTH1_COMMAND = 0xC500
TPM_TAG_RSP_AUTH2_COMMAND = 0xC600

TPM_ORD_CONTINUESELFTEST = 0x53000000
TPM_ORD_FORCECLEAR = 0x5D000000
TPM_ORD_GETCAPABILITY = 0x65000000
TPM_ORD_NV_DEFINESPACE = 0xCC000000
TPM_ORD_NV_READVALUE = 0xCF000000
TPM_ORD_NV_WRITEVALUE = 0xCD000000
TPM_ORD_PCRREAD = 0x15000000
TPM_ORD_PHYSICALDISABLE = 0x70000000
TPM_ORD_PHYSICALENABLE = 0x6F000000
TPM_ORD_PHYSICALSETDEACTIVATED = 0x72000000
TPM_ORD_STARTUP = 0x99000000
TPM_ORD_SAVESTATE = 0x98000000
TSC_ORD_PHYSICALPRESENCE = 0x0A000040
TSC_ORD_RESETESTABLISHMENTBIT = 0x0B000040

STARTUP = {
1:0x0100,
2:0x0200,
3:0x0300
}

PCR= {
  0 :0x00000000,
  1 :0x01000000,
  2 :0x02000000,
  3 :0x03000000,
  4 :0x04000000,
  5 :0x05000000,
  6 :0x06000000,
  7 :0x07000000,
  8 :0x08000000,
  9 :0x09000000,
  10:0x0a000000,
  11:0x0b000000,
  12:0x0c000000,
  13:0x0d000000,
  14:0x0e000000,
  15:0x0f000000,
  16:0x10000000,
  17:0x11000000,
  18:0x12000000,
  19:0x13000000,
  20:0x14000000,
  21:0x15000000,
  22:0x16000000,
  23:0x17000000,
  24:0x18000000,
  25:0x19000000,
  26:0x1a000000,
  27:0x1b000000,
  28:0x1c000000,
  29:0x1d000000,
  30:0x1e000000
}
    
def pcrread( command_argv ):
    """
    The TPM_PCRRead operation provides non-cryptographic reporting  of the contents of a named PCR
    """  
    Size = 0x0E000000
    try:
        Pcr = PCR[int(command_argv[0])]
    except:
        logger().log_bad("Invalid PCR value\n")
        return
    command = struct.pack( COMMAND_FORMAT, TPM_TAG_RQU_COMMAND, Size, TPM_ORD_PCRREAD, Pcr, 0, 0 )
    size = Size >> 0x18
    return ( command, size )

def nvread( command_argv ):
    """
    Read a value from the NV store
    Index, Offset, Size
    """  
    Size = 0x18000000
    command = struct.pack( COMMAND_FORMAT, TPM_TAG_RQU_COMMAND, Size, TPM_ORD_NV_READVALUE, int(command_argv[0], 16), int(command_argv[1], 16), int(command_argv[2], 16) )
    size = Size >> 0x18
    return ( command, size )
    
def startup( command_argv ):
    """
    Execute a tpm_startup command. TPM_Startup is always preceded by TPM_Init, which is the physical indication (a system wide reset) that TPM initialization is necessary
    Type of Startup to be used:
    1: TPM_ST_CLEAR
    2: TPM_ST_STATE
    3: TPM_ST_DEACTIVATED
    """  
    try:
        startupType = STARTUP[int(command_argv[0])]
    except:
        logger().log_bad("Invalid startup type option value\n")
        return
    Size = 0x0E000000
    command = struct.pack( COMMAND_FORMAT, TPM_TAG_RQU_COMMAND, Size, TPM_ORD_STARTUP, startupType, 0, 0 )
    size = Size >> 0x18
    return ( command, size )    

def continueselftest( command_argv ):
    """
    TPM_ContinueSelfTest informs the TPM that it should complete self-test of all TPM functions. The TPM may return success immediately and then perform the self-test, or it may perform the self-test and then return success or failure.
    """
    Size = 0x0A000000
    command = struct.pack( COMMAND_FORMAT, TPM_TAG_RQU_COMMAND, Size, TPM_ORD_CONTINUESELFTEST, 0, 0, 0 )
    size = Size >> 0x18
    return ( command, size )  

def getcap( command_argv ):
    """
    Returns current information regarding the TPM
    CapArea    - Capabilities Area
    SubCapSize - Size of SubCapabilities
    SubCap     - Subcapabilities
    """  
    Size = 0x18000000
    command = struct.pack( COMMAND_FORMAT, TPM_TAG_RQU_COMMAND, Size, TPM_ORD_GETCAPABILITY, int(command_argv[0], 16), int(command_argv[1], 16), int(command_argv[2], 16) )
    size = Size >> 0x18
    return ( command, size )
   
def forceclear( command_argv ):
    Size = 0x0A000000
    command = struct.pack( COMMAND_FORMAT, TPM_TAG_RQU_COMMAND, Size, TPM_ORD_FORCECLEAR, 0, 0, 0 )
    size = Size >> 0x18
    return ( command, size )   
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    