Sync: Have PolicyContextUpdate return TPM_RC

Split-out those TPM 2 command functions that need to be adapted due to the
functions they call returning an error code. Split them out into their own
files so they can be synchronized easier.

Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
This commit is contained in:
Stefan Berger 2025-08-07 10:11:38 -04:00
parent 60783bd058
commit 2c01c2d865
9 changed files with 593 additions and 693 deletions

View File

@ -258,7 +258,12 @@ libtpms_tpm2_la_SOURCES = \
tpm2/PlatformData.c \
tpm2/PlatformPcr.c \
tpm2/Policy_spt.c \
tpm2/PolicyAuthorize.c \
tpm2/PolicyAuthorizeNV.c \
tpm2/PolicyPCR.c \
tpm2/PolicySecret.c \
tpm2/PolicySigned.c \
tpm2/PolicyTicket.c \
tpm2/PolicyTransportSPDM.c \
tpm2/Power.c \
tpm2/PowerPlat.c \

View File

@ -58,385 +58,6 @@
/* */
/********************************************************************************/
#include "Tpm.h"
#include "Policy_spt_fp.h"
#include "PolicySigned_fp.h"
#include "RuntimeProfile_fp.h"
#if CC_PolicySigned // Conditional expansion of this file
/*(See part 3 specification)
// Include an asymmetrically signed authorization to the policy evaluation
*/
// Return Type: TPM_RC
// TPM_RC_CPHASH cpHash was previously set to a different value
// TPM_RC_EXPIRED 'expiration' indicates a time in the past or
// 'expiration' is non-zero but no nonceTPM is present
// TPM_RC_NONCE 'nonceTPM' is not the nonce associated with the
// 'policySession'
// TPM_RC_SCHEME the signing scheme of 'auth' is not supported by the
// TPM
// TPM_RC_SIGNATURE the signature is not genuine
// TPM_RC_SIZE input cpHash has wrong size
TPM_RC
TPM2_PolicySigned(PolicySigned_In* in, // IN: input parameter list
PolicySigned_Out* out // OUT: output parameter list
)
{
TPM_RC result = TPM_RC_SUCCESS;
SESSION* session;
TPM2B_NAME entityName;
TPM2B_DIGEST authHash;
HASH_STATE hashState;
UINT64 authTimeout = 0;
// Input Validation
// Set up local pointers
session = SessionGet(in->policySession); // the session structure
pAssert_RC(session);
// Only do input validation if this is not a trial policy session
if(session->attributes.isTrialPolicy == CLEAR)
{
authTimeout = ComputeAuthTimeout(session, in->expiration, &in->nonceTPM);
result = PolicyParameterChecks(session,
authTimeout,
&in->cpHashA,
&in->nonceTPM,
RC_PolicySigned_nonceTPM,
RC_PolicySigned_cpHashA,
RC_PolicySigned_expiration);
if(result != TPM_RC_SUCCESS)
return result;
// Re-compute the digest being signed
/*(See part 3 specification)
// The digest is computed as:
// aHash := hash ( nonceTPM | expiration | cpHashA | policyRef)
// where:
// hash() the hash associated with the signed authorization
// nonceTPM the nonceTPM value from the TPM2_StartAuthSession .
// response If the authorization is not limited to this
// session, the size of this value is zero.
// expiration time limit on authorization set by authorizing object.
// This 32-bit value is set to zero if the expiration
// time is not being set.
// cpHashA hash of the command parameters for the command being
// approved using the hash algorithm of the PSAP session.
// Set to NULLauth if the authorization is not limited
// to a specific command.
// policyRef hash of an opaque value determined by the authorizing
// object. Set to the NULLdigest if no hash is present.
*/
// Start hash
authHash.t.size = CryptHashStart(&hashState, CryptGetSignHashAlg(&in->auth));
// If there is no digest size, then we don't have a verification function
// for this algorithm (e.g. TPM_ALG_ECDAA) so indicate that it is a
// bad scheme.
if(authHash.t.size == 0)
return TPM_RCS_SCHEME + RC_PolicySigned_auth;
// nonceTPM
CryptDigestUpdate2B(&hashState, &in->nonceTPM.b);
// expiration
CryptDigestUpdateInt(&hashState, sizeof(UINT32), in->expiration);
// cpHashA
CryptDigestUpdate2B(&hashState, &in->cpHashA.b);
// policyRef
CryptDigestUpdate2B(&hashState, &in->policyRef.b);
// Complete digest
CryptHashEnd2B(&hashState, &authHash.b);
// Validate Signature. A TPM_RC_SCHEME, TPM_RC_HANDLE or TPM_RC_SIGNATURE
// error may be returned at this point
result = CryptValidateSignature(in->authObject, &authHash, &in->auth);
if(result != TPM_RC_SUCCESS)
return RcSafeAddToResult(result, RC_PolicySigned_auth);
}
// Internal Data Update
// Update policy with input policyRef and name of authorization key
// These values are updated even if the session is a trial session
PolicyContextUpdate(TPM_CC_PolicySigned,
EntityGetName(in->authObject, &entityName),
&in->policyRef,
&in->cpHashA,
authTimeout,
session);
// Command Output
// Create ticket and timeout buffer if in->expiration < 0 and this is not
// a trial session.
// NOTE: PolicyParameterChecks() makes sure that nonceTPM is present
// when expiration is non-zero.
if(in->expiration < 0 && session->attributes.isTrialPolicy == CLEAR)
{
BOOL expiresOnReset = (in->nonceTPM.t.size == 0);
// Compute policy ticket
authTimeout &= ~EXPIRATION_BIT;
result = TicketComputeAuth(TPM_ST_AUTH_SIGNED,
EntityGetHierarchy(in->authObject),
authTimeout,
expiresOnReset,
&in->cpHashA,
&in->policyRef,
&entityName,
&out->policyTicket);
if(result != TPM_RC_SUCCESS)
return result;
// Generate timeout buffer. The format of output timeout buffer is
// TPM-specific.
// Note: In this implementation, the timeout buffer value is computed after
// the ticket is produced so, when the ticket is checked, the expiration
// flag needs to be extracted before the ticket is checked.
// In the Windows compatible version, the least-significant bit of the
// timeout value is used as a flag to indicate if the authorization expires
// on reset. The flag is the MSb.
out->timeout.t.size = sizeof(authTimeout);
if(expiresOnReset)
authTimeout |= EXPIRATION_BIT;
UINT64_TO_BYTE_ARRAY(authTimeout, out->timeout.t.buffer);
}
else
{
// Generate a null ticket.
// timeout buffer is null
out->timeout.t.size = 0;
// authorization ticket is null
out->policyTicket.tag = TPM_ST_AUTH_SIGNED;
out->policyTicket.hierarchy = TPM_RH_NULL;
out->policyTicket.digest.t.size = 0;
}
return TPM_RC_SUCCESS;
}
#endif // CC_PolicySigned
#include "Tpm.h"
#include "PolicySecret_fp.h"
#if CC_PolicySecret // Conditional expansion of this file
# include "Policy_spt_fp.h"
# include "NV_spt_fp.h"
/*(See part 3 specification)
// Add a secret-based authorization to the policy evaluation
*/
// Return Type: TPM_RC
// TPM_RC_CPHASH cpHash for policy was previously set to a
// value that is not the same as 'cpHashA'
// TPM_RC_EXPIRED 'expiration' indicates a time in the past
// TPM_RC_NONCE 'nonceTPM' does not match the nonce associated
// with 'policySession'
// TPM_RC_SIZE 'cpHashA' is not the size of a digest for the
// hash associated with 'policySession'
TPM_RC
TPM2_PolicySecret(PolicySecret_In* in, // IN: input parameter list
PolicySecret_Out* out // OUT: output parameter list
)
{
TPM_RC result;
SESSION* session;
TPM2B_NAME entityName;
UINT64 authTimeout = 0;
# if CC_ReadOnlyControl
// Don't allow on PIN PASS or PIN FAIL indices when in Read-Only mode
if(gc.readOnly && NvIsPinCountedIndex(in->authHandle))
return TPM_RC_READ_ONLY;
# endif // CC_ReadOnlyControl
// Input Validation
// Get pointer to the session structure
session = SessionGet(in->policySession);
pAssert_RC(session);
//Only do input validation if this is not a trial policy session
if(session->attributes.isTrialPolicy == CLEAR)
{
authTimeout = ComputeAuthTimeout(session, in->expiration, &in->nonceTPM);
result = PolicyParameterChecks(session,
authTimeout,
&in->cpHashA,
&in->nonceTPM,
RC_PolicySecret_nonceTPM,
RC_PolicySecret_cpHashA,
RC_PolicySecret_expiration);
if(result != TPM_RC_SUCCESS)
return result;
}
// Internal Data Update
// Update policy context with input policyRef and name of authorizing key
// This value is computed even for trial sessions. Possibly update the cpHash
PolicyContextUpdate(TPM_CC_PolicySecret,
EntityGetName(in->authHandle, &entityName),
&in->policyRef,
&in->cpHashA,
authTimeout,
session);
// Command Output
// Create ticket and timeout buffer if in->expiration < 0 and this is not
// a trial session.
// NOTE: PolicyParameterChecks() makes sure that nonceTPM is present
// when expiration is non-zero.
if(in->expiration < 0 && session->attributes.isTrialPolicy == CLEAR
&& !NvIsPinPassIndex(in->authHandle))
{
BOOL expiresOnReset = (in->nonceTPM.t.size == 0);
// Compute policy ticket
authTimeout &= ~EXPIRATION_BIT;
result = TicketComputeAuth(TPM_ST_AUTH_SECRET,
EntityGetHierarchy(in->authHandle),
authTimeout,
expiresOnReset,
&in->cpHashA,
&in->policyRef,
&entityName,
&out->policyTicket);
if(result != TPM_RC_SUCCESS)
return result;
// Generate timeout buffer. The format of output timeout buffer is
// TPM-specific.
// Note: In this implementation, the timeout buffer value is computed after
// the ticket is produced so, when the ticket is checked, the expiration
// flag needs to be extracted before the ticket is checked.
out->timeout.t.size = sizeof(authTimeout);
// In the Windows compatible version, the least-significant bit of the
// timeout value is used as a flag to indicate if the authorization expires
// on reset. The flag is the MSb.
if(expiresOnReset)
authTimeout |= EXPIRATION_BIT;
UINT64_TO_BYTE_ARRAY(authTimeout, out->timeout.t.buffer);
}
else
{
// timeout buffer is null
out->timeout.t.size = 0;
// authorization ticket is null
out->policyTicket.tag = TPM_ST_AUTH_SECRET;
out->policyTicket.hierarchy = TPM_RH_NULL;
out->policyTicket.digest.t.size = 0;
}
return TPM_RC_SUCCESS;
}
#endif // CC_PolicySecret
#include "Tpm.h"
#include "PolicyTicket_fp.h"
#if CC_PolicyTicket // Conditional expansion of this file
# include "Policy_spt_fp.h"
/*(See part 3 specification)
// Include ticket to the policy evaluation
*/
// Return Type: TPM_RC
// TPM_RC_CPHASH policy's cpHash was previously set to a different
// value
// TPM_RC_EXPIRED 'timeout' value in the ticket is in the past and the
// ticket has expired
// TPM_RC_SIZE 'timeout' or 'cpHash' has invalid size for the
// TPM_RC_TICKET 'ticket' is not valid
TPM_RC
TPM2_PolicyTicket(PolicyTicket_In* in // IN: input parameter list
)
{
TPM_RC result;
SESSION* session;
UINT64 authTimeout;
TPMT_TK_AUTH ticketToCompare;
TPM_CC commandCode = TPM_CC_PolicySecret;
BOOL expiresOnReset;
// Input Validation
// Get pointer to the session structure
session = SessionGet(in->policySession);
pAssert_RC(session);
// NOTE: A trial policy session is not allowed to use this command.
// A ticket is used in place of a previously given authorization. Since
// a trial policy doesn't actually authenticate, the validated
// ticket is not necessary and, in place of using a ticket, one
// should use the intended authorization for which the ticket
// would be a substitute.
if(session->attributes.isTrialPolicy)
return TPM_RCS_ATTRIBUTES + RC_PolicyTicket_policySession;
// Restore timeout data. The format of timeout buffer is TPM-specific.
// In this implementation, the most significant bit of the timeout value is
// used as the flag to indicate that the ticket expires on TPM Reset or
// TPM Restart. The flag has to be removed before the parameters and ticket
// are checked.
if(in->timeout.t.size != sizeof(UINT64))
return TPM_RCS_SIZE + RC_PolicyTicket_timeout;
authTimeout = BYTE_ARRAY_TO_UINT64(in->timeout.t.buffer);
// extract the flag
expiresOnReset = (authTimeout & EXPIRATION_BIT) != 0;
authTimeout &= ~EXPIRATION_BIT;
// Do the normal checks on the cpHashA and timeout values
result = PolicyParameterChecks(session,
authTimeout,
&in->cpHashA,
NULL, // no nonce
0, // no bad nonce return
RC_PolicyTicket_cpHashA,
RC_PolicyTicket_timeout);
if(result != TPM_RC_SUCCESS)
return result;
// Validate Ticket
// Re-generate policy ticket by input parameters
result = TicketComputeAuth(in->ticket.tag,
in->ticket.hierarchy,
authTimeout,
expiresOnReset,
&in->cpHashA,
&in->policyRef,
&in->authName,
&ticketToCompare);
if(result != TPM_RC_SUCCESS)
return result;
// Compare generated digest with input ticket digest
if(!MemoryEqual2B(&in->ticket.digest.b, &ticketToCompare.digest.b))
return TPM_RCS_TICKET + RC_PolicyTicket_ticket;
// Internal Data Update
// Is this ticket to take the place of a TPM2_PolicySigned() or
// a TPM2_PolicySecret()?
if(in->ticket.tag == TPM_ST_AUTH_SIGNED)
commandCode = TPM_CC_PolicySigned;
else if(in->ticket.tag == TPM_ST_AUTH_SECRET)
commandCode = TPM_CC_PolicySecret;
else
// There could only be two possible tag values. Any other value should
// be caught by the ticket validation process.
FAIL(FATAL_ERROR_INTERNAL);
// Update policy context
PolicyContextUpdate(commandCode,
&in->authName,
&in->policyRef,
&in->cpHashA,
authTimeout,
session);
return TPM_RC_SUCCESS;
}
#endif // CC_PolicyTicket
#include "Tpm.h"
#include "PolicyOR_fp.h"
@ -1138,105 +759,6 @@ TPM2_PolicyDuplicationSelect(
#endif // CC_PolicyDuplicationSelect
#include "Tpm.h"
#include "PolicyAuthorize_fp.h"
#if CC_PolicyAuthorize // Conditional expansion of this file
# include "Policy_spt_fp.h"
/*(See part 3 specification)
// Change policy by a signature from authority
*/
// Return Type: TPM_RC
// TPM_RC_HASH hash algorithm in 'keyName' is not supported
// TPM_RC_SIZE 'keyName' is not the correct size for its hash algorithm
// TPM_RC_VALUE the current policyDigest of 'policySession' does not
// match 'approvedPolicy'; or 'checkTicket' doesn't match
// the provided values
TPM_RC
TPM2_PolicyAuthorize(PolicyAuthorize_In* in // IN: input parameter list
)
{
TPM_RC result = TPM_RC_SUCCESS;
SESSION* session;
TPM2B_DIGEST authHash;
HASH_STATE hashState;
TPMT_TK_VERIFIED ticket;
TPM_ALG_ID hashAlg;
UINT16 digestSize;
// Input Validation
// Get pointer to the session structure
session = SessionGet(in->policySession);
pAssert_RC(session);
if(in->keySign.t.size < 2)
{
return TPM_RCS_SIZE + RC_PolicyAuthorize_keySign;
}
// Extract from the Name of the key, the algorithm used to compute its Name
hashAlg = BYTE_ARRAY_TO_UINT16(in->keySign.t.name);
// 'keySign' parameter needs to use a supported hash algorithm, otherwise
// can't tell how large the digest should be
if(!CryptHashIsValidAlg(hashAlg, FALSE))
return TPM_RCS_HASH + RC_PolicyAuthorize_keySign;
digestSize = CryptHashGetDigestSize(hashAlg);
if(digestSize != (in->keySign.t.size - 2))
return TPM_RCS_SIZE + RC_PolicyAuthorize_keySign;
//If this is a trial policy, skip all validations
if(session->attributes.isTrialPolicy == CLEAR)
{
// Check that "approvedPolicy" matches the current value of the
// policyDigest in policy session
if(!MemoryEqual2B(&session->u2.policyDigest.b, &in->approvedPolicy.b))
return TPM_RCS_VALUE + RC_PolicyAuthorize_approvedPolicy;
// Validate ticket TPMT_TK_VERIFIED
// Compute aHash. The authorizing object sign a digest
// aHash := hash(approvedPolicy || policyRef).
// Start hash
authHash.t.size = CryptHashStart(&hashState, hashAlg);
// add approvedPolicy
CryptDigestUpdate2B(&hashState, &in->approvedPolicy.b);
// add policyRef
CryptDigestUpdate2B(&hashState, &in->policyRef.b);
// complete hash
CryptHashEnd2B(&hashState, &authHash.b);
// re-compute TPMT_TK_VERIFIED
result = TicketComputeVerified(in->checkTicket.hierarchy, &authHash,
&in->keySign, &ticket);
if(result != TPM_RC_SUCCESS)
return result;
// Compare ticket digest. If not match, return error
if(!MemoryEqual2B(&in->checkTicket.digest.b, &ticket.digest.b))
return TPM_RCS_VALUE + RC_PolicyAuthorize_checkTicket;
}
// Internal Data Update
// Set policyDigest to zero digest
PolicyDigestClear(session);
// Update policyDigest
PolicyContextUpdate(
TPM_CC_PolicyAuthorize, &in->keySign, &in->policyRef, NULL, 0, session);
return TPM_RC_SUCCESS;
}
#endif // CC_PolicyAuthorize
#include "Tpm.h"
#include "PolicyAuthValue_fp.h"
@ -1479,96 +1001,6 @@ TPM2_PolicyTemplate(PolicyTemplate_In* in // IN: input parameter list
#endif // CC_PolicyTemplate
#include "Tpm.h"
#if CC_PolicyAuthorizeNV // Conditional expansion of this file
# include "PolicyAuthorizeNV_fp.h"
# include "Policy_spt_fp.h"
# include "Marshal.h"
/*(See part 3 specification)
// Change policy by a signature from authority
*/
// Return Type: TPM_RC
// TPM_RC_HASH hash algorithm in 'keyName' is not supported or is not
// the same as the hash algorithm of the policy session
// TPM_RC_SIZE 'keyName' is not the correct size for its hash algorithm
// TPM_RC_VALUE the current policyDigest of 'policySession' does not
// match 'approvedPolicy'; or 'checkTicket' doesn't match
// the provided values
TPM_RC
TPM2_PolicyAuthorizeNV(PolicyAuthorizeNV_In* in)
{
SESSION* session;
TPM_RC result;
NV_REF locator;
NV_INDEX* nvIndex = NvGetIndexInfo(in->nvIndex, &locator);
TPM2B_NAME name;
TPMT_HA policyInNv = {
.hashAlg = 0, // libpms added: Coverity
};
BYTE nvTemp[sizeof(TPMT_HA)];
BYTE* buffer = nvTemp;
INT32 size;
// Input Validation
// Get pointer to the session structure
session = SessionGet(in->policySession);
pAssert_RC(session);
// Skip checks if this is a trial policy
if(!session->attributes.isTrialPolicy)
{
// Check the authorizations for reading
// Common read access checks. NvReadAccessChecks() returns
// TPM_RC_NV_AUTHORIZATION, TPM_RC_NV_LOCKED, or TPM_RC_NV_UNINITIALIZED
// error may be returned at this point
result = NvReadAccessChecks(
in->authHandle, in->nvIndex, nvIndex->publicArea.attributes);
if(result != TPM_RC_SUCCESS)
return result;
// Read the contents of the index into a temp buffer
size = MIN(nvIndex->publicArea.dataSize, sizeof(TPMT_HA));
NvGetIndexData(nvIndex, locator, 0, (UINT16)size, nvTemp);
// Unmarshal the contents of the buffer into the internal format of a
// TPMT_HA so that the hash and digest elements can be accessed from the
// structure rather than the byte array that is in the Index (written by
// user of the Index).
result = TPMT_HA_Unmarshal(&policyInNv, &buffer, &size, FALSE);
if(result != TPM_RC_SUCCESS)
return result;
// Verify that the hash is the same
if(policyInNv.hashAlg != session->authHashAlg)
return TPM_RC_HASH;
// See if the contents of the digest in the Index matches the value
// in the policy
if(!MemoryEqual(&policyInNv.digest,
&session->u2.policyDigest.t.buffer,
session->u2.policyDigest.t.size))
return TPM_RC_VALUE;
}
// Internal Data Update
// Set policyDigest to zero digest
PolicyDigestClear(session);
// Update policyDigest
PolicyContextUpdate(TPM_CC_PolicyAuthorizeNV,
EntityGetName(in->nvIndex, &name),
NULL,
NULL,
0,
session);
return TPM_RC_SUCCESS;
}
#endif // CC_PolicyAuthorizeNV
#include "Tpm.h"
#include "PolicyCapability_fp.h"

View File

@ -0,0 +1,98 @@
// SPDX-License-Identifier: BSD-2-Clause
#include "Tpm.h"
#include "PolicyAuthorize_fp.h"
#if CC_PolicyAuthorize // Conditional expansion of this file
# include "Policy_spt_fp.h"
/*(See part 3 specification)
// Change policy by a signature from authority
*/
// Return Type: TPM_RC
// TPM_RC_HASH hash algorithm in 'keyName' is not supported
// TPM_RC_SIZE 'keyName' is not the correct size for its hash algorithm
// TPM_RC_VALUE the current policyDigest of 'policySession' does not
// match 'approvedPolicy'; or 'checkTicket' doesn't match
// the provided values
TPM_RC
TPM2_PolicyAuthorize(PolicyAuthorize_In* in // IN: input parameter list
)
{
TPM_RC result = TPM_RC_SUCCESS;
SESSION* session;
TPM2B_DIGEST authHash;
HASH_STATE hashState;
TPMT_TK_VERIFIED ticket;
TPM_ALG_ID hashAlg;
UINT16 digestSize;
// Input Validation
// Get pointer to the session structure
session = SessionGet(in->policySession);
pAssert_RC(session);
if(in->keySign.t.size < 2)
{
return TPM_RCS_SIZE + RC_PolicyAuthorize_keySign;
}
// Extract from the Name of the key, the algorithm used to compute its Name
hashAlg = BYTE_ARRAY_TO_UINT16(in->keySign.t.name);
// 'keySign' parameter needs to use a supported hash algorithm, otherwise
// can't tell how large the digest should be
if(!CryptHashIsValidAlg(hashAlg, FALSE))
return TPM_RCS_HASH + RC_PolicyAuthorize_keySign;
digestSize = CryptHashGetDigestSize(hashAlg);
if(digestSize != (in->keySign.t.size - 2))
return TPM_RCS_SIZE + RC_PolicyAuthorize_keySign;
//If this is a trial policy, skip all validations
if(session->attributes.isTrialPolicy == CLEAR)
{
// Check that "approvedPolicy" matches the current value of the
// policyDigest in policy session
if(!MemoryEqual2B(&session->u2.policyDigest.b, &in->approvedPolicy.b))
return TPM_RCS_VALUE + RC_PolicyAuthorize_approvedPolicy;
// Validate ticket TPMT_TK_VERIFIED
// Compute aHash. The authorizing object sign a digest
// aHash := hash(approvedPolicy || policyRef).
// Start hash
authHash.t.size = CryptHashStart(&hashState, hashAlg);
// add approvedPolicy
CryptDigestUpdate2B(&hashState, &in->approvedPolicy.b);
// add policyRef
CryptDigestUpdate2B(&hashState, &in->policyRef.b);
// complete hash
CryptHashEnd2B(&hashState, &authHash.b);
// re-compute TPMT_TK_VERIFIED
result = TicketComputeVerified(
in->checkTicket.hierarchy, &authHash, &in->keySign, &ticket);
if(result != TPM_RC_SUCCESS)
return result;
// Compare ticket digest. If not match, return error
if(!MemoryEqual2B(&in->checkTicket.digest.b, &ticket.digest.b))
return TPM_RCS_VALUE + RC_PolicyAuthorize_checkTicket;
}
// Internal Data Update
// Set policyDigest to zero digest
PolicyDigestClear(session);
// Update policyDigest
return PolicyContextUpdate(
TPM_CC_PolicyAuthorize, &in->keySign, &in->policyRef, NULL, 0, session);
}
#endif // CC_PolicyAuthorize

View File

@ -0,0 +1,91 @@
// SPDX-License-Identifier: BSD-2-Clause
#include "Tpm.h"
#if CC_PolicyAuthorizeNV // Conditional expansion of this file
# include "PolicyAuthorizeNV_fp.h"
# include "Policy_spt_fp.h"
# include "Marshal.h"
/*(See part 3 specification)
// Change policy by a signature from authority
*/
// Return Type: TPM_RC
// TPM_RC_HASH hash algorithm in 'keyName' is not supported or is not
// the same as the hash algorithm of the policy session
// TPM_RC_SIZE 'keyName' is not the correct size for its hash algorithm
// TPM_RC_VALUE the current policyDigest of 'policySession' does not
// match 'approvedPolicy'; or 'checkTicket' doesn't match
// the provided values
TPM_RC
TPM2_PolicyAuthorizeNV(PolicyAuthorizeNV_In* in)
{
SESSION* session;
TPM_RC result;
NV_REF locator;
NV_INDEX* nvIndex = NvGetIndexInfo(in->nvIndex, &locator);
TPM2B_NAME name;
TPMT_HA policyInNv = {
.hashAlg = 0, // libpms added: Coverity
};
BYTE nvTemp[sizeof(TPMT_HA)];
BYTE* buffer = nvTemp;
INT32 size;
// Input Validation
// Get pointer to the session structure
session = SessionGet(in->policySession);
pAssert_RC(session);
// Skip checks if this is a trial policy
if(!session->attributes.isTrialPolicy)
{
// Check the authorizations for reading
// Common read access checks. NvReadAccessChecks() returns
// TPM_RC_NV_AUTHORIZATION, TPM_RC_NV_LOCKED, or TPM_RC_NV_UNINITIALIZED
// error may be returned at this point
result = NvReadAccessChecks(
in->authHandle, in->nvIndex, nvIndex->publicArea.attributes);
if(result != TPM_RC_SUCCESS)
return result;
// Read the contents of the index into a temp buffer
size = MIN(nvIndex->publicArea.dataSize, sizeof(TPMT_HA));
NvGetIndexData(nvIndex, locator, 0, (UINT16)size, nvTemp);
// Unmarshal the contents of the buffer into the internal format of a
// TPMT_HA so that the hash and digest elements can be accessed from the
// structure rather than the byte array that is in the Index (written by
// user of the Index).
result = TPMT_HA_Unmarshal(&policyInNv, &buffer, &size, FALSE);
if(result != TPM_RC_SUCCESS)
return result;
// Verify that the hash is the same
if(policyInNv.hashAlg != session->authHashAlg)
return TPM_RC_HASH;
// See if the contents of the digest in the Index matches the value
// in the policy
if(!MemoryEqual(&policyInNv.digest,
&session->u2.policyDigest.t.buffer,
session->u2.policyDigest.t.size))
return TPM_RC_VALUE;
}
// Internal Data Update
// Set policyDigest to zero digest
PolicyDigestClear(session);
// Update policyDigest
return PolicyContextUpdate(TPM_CC_PolicyAuthorizeNV,
EntityGetName(in->nvIndex, &name),
NULL,
NULL,
0,
session);
}
#endif // CC_PolicyAuthorize

120
src/tpm2/PolicySecret.c Normal file
View File

@ -0,0 +1,120 @@
// SPDX-License-Identifier: BSD-2-Clause
#include "Tpm.h"
#include "PolicySecret_fp.h"
#if CC_PolicySecret // Conditional expansion of this file
# include "Policy_spt_fp.h"
# include "NV_spt_fp.h"
/*(See part 3 specification)
// Add a secret-based authorization to the policy evaluation
*/
// Return Type: TPM_RC
// TPM_RC_CPHASH cpHash for policy was previously set to a
// value that is not the same as 'cpHashA'
// TPM_RC_EXPIRED 'expiration' indicates a time in the past
// TPM_RC_NONCE 'nonceTPM' does not match the nonce associated
// with 'policySession'
// TPM_RC_SIZE 'cpHashA' is not the size of a digest for the
// hash associated with 'policySession'
TPM_RC
TPM2_PolicySecret(PolicySecret_In* in, // IN: input parameter list
PolicySecret_Out* out // OUT: output parameter list
)
{
TPM_RC result;
SESSION* session;
TPM2B_NAME entityName;
UINT64 authTimeout = 0;
// Input Validation
# if CC_ReadOnlyControl
// Don't allow on PIN PASS or PIN FAIL indices when in Read-Only mode
if(gc.readOnly && NvIsPinCountedIndex(in->authHandle))
return TPM_RC_READ_ONLY;
# endif // CC_ReadOnlyControl
// Get pointer to the session structure
session = SessionGet(in->policySession);
pAssert_RC(session);
//Only do input validation if this is not a trial policy session
if(session->attributes.isTrialPolicy == CLEAR)
{
authTimeout = ComputeAuthTimeout(session, in->expiration, &in->nonceTPM);
result = PolicyParameterChecks(session,
authTimeout,
&in->cpHashA,
&in->nonceTPM,
RC_PolicySecret_nonceTPM,
RC_PolicySecret_cpHashA,
RC_PolicySecret_expiration);
if(result != TPM_RC_SUCCESS)
return result;
}
// Internal Data Update
// Update policy context with input policyRef and name of authorizing key
// This value is computed even for trial sessions. Possibly update the cpHash
result = PolicyContextUpdate(TPM_CC_PolicySecret,
EntityGetName(in->authHandle, &entityName),
&in->policyRef,
&in->cpHashA,
authTimeout,
session);
if(result != TPM_RC_SUCCESS)
{
return result;
}
// Command Output
// Create ticket and timeout buffer if in->expiration < 0 and this is not
// a trial session.
// NOTE: PolicyParameterChecks() makes sure that nonceTPM is present
// when expiration is non-zero.
if(in->expiration < 0 && session->attributes.isTrialPolicy == CLEAR
&& !NvIsPinPassIndex(in->authHandle))
{
BOOL expiresOnReset = (in->nonceTPM.t.size == 0);
// Compute policy ticket
authTimeout &= ~EXPIRATION_BIT;
result = TicketComputeAuth(TPM_ST_AUTH_SECRET,
EntityGetHierarchy(in->authHandle),
authTimeout,
expiresOnReset,
&in->cpHashA,
&in->policyRef,
&entityName,
&out->policyTicket);
if(result != TPM_RC_SUCCESS)
return result;
// Generate timeout buffer. The format of output timeout buffer is
// TPM-specific.
// Note: In this implementation, the timeout buffer value is computed after
// the ticket is produced so, when the ticket is checked, the expiration
// flag needs to be extracted before the ticket is checked.
out->timeout.t.size = sizeof(authTimeout);
// In the Windows compatible version, the least-significant bit of the
// timeout value is used as a flag to indicate if the authorization expires
// on reset. The flag is the MSb.
if(expiresOnReset)
authTimeout |= EXPIRATION_BIT;
UINT64_TO_BYTE_ARRAY(authTimeout, out->timeout.t.buffer);
}
else
{
// timeout buffer is null
out->timeout.t.size = 0;
// authorization ticket is null
out->policyTicket.tag = TPM_ST_AUTH_SECRET;
out->policyTicket.hierarchy = TPM_RH_NULL;
out->policyTicket.digest.t.size = 0;
}
return result;
}
#endif // CC_PolicySecret

164
src/tpm2/PolicySigned.c Normal file
View File

@ -0,0 +1,164 @@
// SPDX-License-Identifier: BSD-2-Clause
#include "Tpm.h"
#include "Policy_spt_fp.h"
#include "PolicySigned_fp.h"
#if CC_PolicySigned // Conditional expansion of this file
/*(See part 3 specification)
// Include an asymmetrically signed authorization to the policy evaluation
*/
// Return Type: TPM_RC
// TPM_RC_CPHASH cpHash was previously set to a different value
// TPM_RC_EXPIRED 'expiration' indicates a time in the past or
// 'expiration' is non-zero but no nonceTPM is present
// TPM_RC_NONCE 'nonceTPM' is not the nonce associated with the
// 'policySession'
// TPM_RC_SCHEME the signing scheme of 'auth' is not supported by the
// TPM
// TPM_RC_SIGNATURE the signature is not genuine
// TPM_RC_SIZE input cpHash has wrong size
TPM_RC
TPM2_PolicySigned(PolicySigned_In* in, // IN: input parameter list
PolicySigned_Out* out // OUT: output parameter list
)
{
TPM_RC result = TPM_RC_SUCCESS;
SESSION* session;
TPM2B_NAME entityName;
TPM2B_DIGEST authHash;
HASH_STATE hashState;
UINT64 authTimeout = 0;
// Input Validation
// Set up local pointers
session = SessionGet(in->policySession); // the session structure
pAssert_RC(session);
// Only do input validation if this is not a trial policy session
if(session->attributes.isTrialPolicy == CLEAR)
{
authTimeout = ComputeAuthTimeout(session, in->expiration, &in->nonceTPM);
result = PolicyParameterChecks(session,
authTimeout,
&in->cpHashA,
&in->nonceTPM,
RC_PolicySigned_nonceTPM,
RC_PolicySigned_cpHashA,
RC_PolicySigned_expiration);
if(result != TPM_RC_SUCCESS)
return result;
// Re-compute the digest being signed
/*(See part 3 specification)
// The digest is computed as:
// aHash := hash ( nonceTPM | expiration | cpHashA | policyRef)
// where:
// hash() the hash associated with the signed authorization
// nonceTPM the nonceTPM value from the TPM2_StartAuthSession .
// response If the authorization is not limited to this
// session, the size of this value is zero.
// expiration time limit on authorization set by authorizing object.
// This 32-bit value is set to zero if the expiration
// time is not being set.
// cpHashA hash of the command parameters for the command being
// approved using the hash algorithm of the PSAP session.
// Set to NULLauth if the authorization is not limited
// to a specific command.
// policyRef hash of an opaque value determined by the authorizing
// object. Set to the NULLdigest if no hash is present.
*/
// Start hash
authHash.t.size = CryptHashStart(&hashState, CryptGetSignHashAlg(&in->auth));
// If there is no digest size, then we don't have a verification function
// for this algorithm (e.g. TPM_ALG_ECDAA) so indicate that it is a
// bad scheme.
if(authHash.t.size == 0)
return TPM_RCS_SCHEME + RC_PolicySigned_auth;
// nonceTPM
CryptDigestUpdate2B(&hashState, &in->nonceTPM.b);
// expiration
CryptDigestUpdateInt(&hashState, sizeof(UINT32), in->expiration);
// cpHashA
CryptDigestUpdate2B(&hashState, &in->cpHashA.b);
// policyRef
CryptDigestUpdate2B(&hashState, &in->policyRef.b);
// Complete digest
CryptHashEnd2B(&hashState, &authHash.b);
// Validate Signature. A TPM_RC_SCHEME, TPM_RC_HANDLE or TPM_RC_SIGNATURE
// error may be returned at this point
result = CryptValidateSignature(in->authObject, &authHash, &in->auth);
if(result != TPM_RC_SUCCESS)
return RcSafeAddToResult(result, RC_PolicySigned_auth);
}
// Internal Data Update
// Update policy with input policyRef and name of authorization key
// These values are updated even if the session is a trial session
result = PolicyContextUpdate(TPM_CC_PolicySigned,
EntityGetName(in->authObject, &entityName),
&in->policyRef,
&in->cpHashA,
authTimeout,
session);
if(result != TPM_RC_SUCCESS)
{
return result;
}
// Command Output
// Create ticket and timeout buffer if in->expiration < 0 and this is not
// a trial session.
// NOTE: PolicyParameterChecks() makes sure that nonceTPM is present
// when expiration is non-zero.
if(in->expiration < 0 && session->attributes.isTrialPolicy == CLEAR)
{
BOOL expiresOnReset = (in->nonceTPM.t.size == 0);
// Compute policy ticket
authTimeout &= ~EXPIRATION_BIT;
result = TicketComputeAuth(TPM_ST_AUTH_SIGNED,
EntityGetHierarchy(in->authObject),
authTimeout,
expiresOnReset,
&in->cpHashA,
&in->policyRef,
&entityName,
&out->policyTicket);
if(result != TPM_RC_SUCCESS)
return result;
// Generate timeout buffer. The format of output timeout buffer is
// TPM-specific.
// Note: In this implementation, the timeout buffer value is computed after
// the ticket is produced so, when the ticket is checked, the expiration
// flag needs to be extracted before the ticket is checked.
// In the Windows compatible version, the least-significant bit of the
// timeout value is used as a flag to indicate if the authorization expires
// on reset. The flag is the MSb.
out->timeout.t.size = sizeof(authTimeout);
if(expiresOnReset)
authTimeout |= EXPIRATION_BIT;
UINT64_TO_BYTE_ARRAY(authTimeout, out->timeout.t.buffer);
}
else
{
// Generate a null ticket.
// timeout buffer is null
out->timeout.t.size = 0;
// authorization ticket is null
out->policyTicket.tag = TPM_ST_AUTH_SIGNED;
out->policyTicket.hierarchy = TPM_RH_NULL;
out->policyTicket.digest.t.size = 0;
}
return result;
}
#endif // CC_PolicySigned

107
src/tpm2/PolicyTicket.c Normal file
View File

@ -0,0 +1,107 @@
// SPDX-License-Identifier: BSD-2-Clause
#include "Tpm.h"
#include "PolicyTicket_fp.h"
#if CC_PolicyTicket // Conditional expansion of this file
# include "Policy_spt_fp.h"
/*(See part 3 specification)
// Include ticket to the policy evaluation
*/
// Return Type: TPM_RC
// TPM_RC_CPHASH policy's cpHash was previously set to a different
// value
// TPM_RC_EXPIRED 'timeout' value in the ticket is in the past and the
// ticket has expired
// TPM_RC_SIZE 'timeout' or 'cpHash' has invalid size for the
// TPM_RC_TICKET 'ticket' is not valid
TPM_RC
TPM2_PolicyTicket(PolicyTicket_In* in // IN: input parameter list
)
{
TPM_RC result;
SESSION* session;
UINT64 authTimeout;
TPMT_TK_AUTH ticketToCompare;
TPM_CC commandCode = TPM_CC_PolicySecret;
BOOL expiresOnReset;
// Input Validation
// Get pointer to the session structure
session = SessionGet(in->policySession);
pAssert_RC(session);
// NOTE: A trial policy session is not allowed to use this command.
// A ticket is used in place of a previously given authorization. Since
// a trial policy doesn't actually authenticate, the validated
// ticket is not necessary and, in place of using a ticket, one
// should use the intended authorization for which the ticket
// would be a substitute.
if(session->attributes.isTrialPolicy)
return TPM_RCS_ATTRIBUTES + RC_PolicyTicket_policySession;
// Restore timeout data. The format of timeout buffer is TPM-specific.
// In this implementation, the most significant bit of the timeout value is
// used as the flag to indicate that the ticket expires on TPM Reset or
// TPM Restart. The flag has to be removed before the parameters and ticket
// are checked.
if(in->timeout.t.size != sizeof(UINT64))
return TPM_RCS_SIZE + RC_PolicyTicket_timeout;
authTimeout = BYTE_ARRAY_TO_UINT64(in->timeout.t.buffer);
// extract the flag
expiresOnReset = (authTimeout & EXPIRATION_BIT) != 0;
authTimeout &= ~EXPIRATION_BIT;
// Do the normal checks on the cpHashA and timeout values
result = PolicyParameterChecks(session,
authTimeout,
&in->cpHashA,
NULL, // no nonce
0, // no bad nonce return
RC_PolicyTicket_cpHashA,
RC_PolicyTicket_timeout);
if(result != TPM_RC_SUCCESS)
return result;
// Validate Ticket
// Re-generate policy ticket by input parameters
result = TicketComputeAuth(in->ticket.tag,
in->ticket.hierarchy,
authTimeout,
expiresOnReset,
&in->cpHashA,
&in->policyRef,
&in->authName,
&ticketToCompare);
if(result != TPM_RC_SUCCESS)
return result;
// Compare generated digest with input ticket digest
if(!MemoryEqual2B(&in->ticket.digest.b, &ticketToCompare.digest.b))
return TPM_RCS_TICKET + RC_PolicyTicket_ticket;
// Internal Data Update
// Is this ticket to take the place of a TPM2_PolicySigned() or
// a TPM2_PolicySecret()?
if(in->ticket.tag == TPM_ST_AUTH_SIGNED)
commandCode = TPM_CC_PolicySigned;
else if(in->ticket.tag == TPM_ST_AUTH_SECRET)
commandCode = TPM_CC_PolicySecret;
else
// There could only be two possible tag values. Any other value should
// be caught by the ticket validation process.
FAIL(FATAL_ERROR_INTERNAL);
// Update policy context
return PolicyContextUpdate(commandCode,
&in->authName,
&in->policyRef,
&in->cpHashA,
authTimeout,
session);
}
#endif // CC_PolicyTicket

View File

@ -1,63 +1,4 @@
/********************************************************************************/
/* */
/* Policy Command Support */
/* Written by Ken Goldman */
/* IBM Thomas J. Watson Research Center */
/* $Id: Policy_spt.c 1594 2020-03-26 22:15:48Z kgoldman $ */
/* */
/* Licenses and Notices */
/* */
/* 1. Copyright Licenses: */
/* */
/* - Trusted Computing Group (TCG) grants to the user of the source code in */
/* this specification (the "Source Code") a worldwide, irrevocable, */
/* nonexclusive, royalty free, copyright license to reproduce, create */
/* derivative works, distribute, display and perform the Source Code and */
/* derivative works thereof, and to grant others the rights granted herein. */
/* */
/* - The TCG grants to the user of the other parts of the specification */
/* (other than the Source Code) the rights to reproduce, distribute, */
/* display, and perform the specification solely for the purpose of */
/* developing products based on such documents. */
/* */
/* 2. Source Code Distribution Conditions: */
/* */
/* - Redistributions of Source Code must retain the above copyright licenses, */
/* this list of conditions and the following disclaimers. */
/* */
/* - Redistributions in binary form must reproduce the above copyright */
/* licenses, this list of conditions and the following disclaimers in the */
/* documentation and/or other materials provided with the distribution. */
/* */
/* 3. Disclaimers: */
/* */
/* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */
/* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */
/* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */
/* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */
/* Contact TCG Administration (admin@trustedcomputinggroup.org) for */
/* information on specification licensing rights available through TCG */
/* membership agreements. */
/* */
/* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */
/* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */
/* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */
/* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */
/* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */
/* */
/* - Without limitation, TCG and its members and licensors disclaim all */
/* liability, including liability for infringement of any proprietary */
/* rights, relating to use of information in this specification and to the */
/* implementation of this specification, and TCG disclaims all liability for */
/* cost of procurement of substitute goods or services, lost profits, loss */
/* of use, loss of data or any incidental, consequential, direct, indirect, */
/* or special damages, whether under contract, tort, warranty or otherwise, */
/* arising in any way out of use or reliance upon this specification or any */
/* information herein. */
/* */
/* (c) Copyright IBM Corp. and others, 2016 - 2020 */
/* */
/********************************************************************************/
// SPDX-License-Identifier: BSD-2-Clause
//** Includes
#include "Tpm.h"
@ -121,7 +62,7 @@ PolicyParameterChecks(SESSION* session,
// objectName to it. This will also update the cpHash if it is present.
//
// Return Type: void
void PolicyContextUpdate(
TPM_RC PolicyContextUpdate(
TPM_CC commandCode, // IN: command code
TPM2B_NAME* name, // IN: name of entity
TPM2B_NONCE* ref, // IN: the reference data
@ -136,8 +77,8 @@ void PolicyContextUpdate(
CryptHashStart(&hashState, session->authHashAlg);
// policyDigest size should always be the digest size of session hash algorithm.
pAssert(session->u2.policyDigest.t.size
== CryptHashGetDigestSize(session->authHashAlg));
pAssert_RC(session->u2.policyDigest.t.size
== CryptHashGetDigestSize(session->authHashAlg));
// add old digest
CryptDigestUpdate2B(&hashState, &session->u2.policyDigest.b);
@ -186,7 +127,8 @@ void PolicyContextUpdate(
if(session->timeout == 0 || session->timeout > policyTimeout)
session->timeout = policyTimeout;
}
return;
VERIFY_NOT_FAILED();
return TPM_RC_SUCCESS;
}
//*** ComputeAuthTimeout()
// This function is used to determine what the authorization timeout value for

View File

@ -1,63 +1,4 @@
/********************************************************************************/
/* */
/* */
/* Written by Ken Goldman */
/* IBM Thomas J. Watson Research Center */
/* $Id: Policy_spt_fp.h 1490 2019-07-26 21:13:22Z kgoldman $ */
/* */
/* Licenses and Notices */
/* */
/* 1. Copyright Licenses: */
/* */
/* - Trusted Computing Group (TCG) grants to the user of the source code in */
/* this specification (the "Source Code") a worldwide, irrevocable, */
/* nonexclusive, royalty free, copyright license to reproduce, create */
/* derivative works, distribute, display and perform the Source Code and */
/* derivative works thereof, and to grant others the rights granted herein. */
/* */
/* - The TCG grants to the user of the other parts of the specification */
/* (other than the Source Code) the rights to reproduce, distribute, */
/* display, and perform the specification solely for the purpose of */
/* developing products based on such documents. */
/* */
/* 2. Source Code Distribution Conditions: */
/* */
/* - Redistributions of Source Code must retain the above copyright licenses, */
/* this list of conditions and the following disclaimers. */
/* */
/* - Redistributions in binary form must reproduce the above copyright */
/* licenses, this list of conditions and the following disclaimers in the */
/* documentation and/or other materials provided with the distribution. */
/* */
/* 3. Disclaimers: */
/* */
/* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */
/* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */
/* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */
/* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */
/* Contact TCG Administration (admin@trustedcomputinggroup.org) for */
/* information on specification licensing rights available through TCG */
/* membership agreements. */
/* */
/* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */
/* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */
/* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */
/* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */
/* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */
/* */
/* - Without limitation, TCG and its members and licensors disclaim all */
/* liability, including liability for infringement of any proprietary */
/* rights, relating to use of information in this specification and to the */
/* implementation of this specification, and TCG disclaims all liability for */
/* cost of procurement of substitute goods or services, lost profits, loss */
/* of use, loss of data or any incidental, consequential, direct, indirect, */
/* or special damages, whether under contract, tort, warranty or otherwise, */
/* arising in any way out of use or reliance upon this specification or any */
/* information herein. */
/* */
/* (c) Copyright IBM Corp. and others, 2016 */
/* */
/********************************************************************************/
// SPDX-License-Identifier: BSD-2-Clause
/*(Auto-generated)
* Created by TpmPrototypes; Version 3.0 July 18, 2017
@ -87,7 +28,7 @@ PolicyParameterChecks(SESSION* session,
// objectName to it. This will also update the cpHash if it is present.
//
// Return Type: void
void PolicyContextUpdate(
TPM_RC PolicyContextUpdate(
TPM_CC commandCode, // IN: command code
TPM2B_NAME* name, // IN: name of entity
TPM2B_NONCE* ref, // IN: the reference data