1// This file was extracted from the TCG Published
2// Trusted Platform Module Library
3// Part 4: Supporting Routines
4// Family "2.0"
5// Level 00 Revision 01.16
6// October 30, 2014
7
8#include "InternalRoutines.h"
9#include "Attest_spt_fp.h"
10//
11//
12//          Functions
13//
14//          FillInAttestInfo()
15//
16//     Fill in common fields of TPMS_ATTEST structure.
17//
18//     Error Returns                     Meaning
19//
20//     TPM_RC_KEY                        key referenced by signHandle is not a signing key
21//     TPM_RC_SCHEME                     both scheme and key's default scheme are empty; or scheme is
22//                                       empty while key's default scheme requires explicit input scheme (split
23//                                       signing); or non-empty default key scheme differs from scheme
24//
25TPM_RC
26FillInAttestInfo(
27     TPMI_DH_OBJECT         signHandle,            //   IN: handle of signing object
28     TPMT_SIG_SCHEME       *scheme,                //   IN/OUT: scheme to be used for signing
29     TPM2B_DATA            *data,                  //   IN: qualifying data
30     TPMS_ATTEST           *attest                 //   OUT: attest structure
31     )
32{
33     TPM_RC                         result;
34     TPMI_RH_HIERARCHY              signHierarhcy;
35     result = CryptSelectSignScheme(signHandle, scheme);
36     if(result != TPM_RC_SUCCESS)
37         return result;
38     // Magic number
39     attest->magic = TPM_GENERATED_VALUE;
40     if(signHandle == TPM_RH_NULL)
41     {
42         BYTE     *buffer;
43         INT32     bufferSize;
44         // For null sign handle, the QN is TPM_RH_NULL
45         buffer = attest->qualifiedSigner.t.name;
46         bufferSize = sizeof(TPM_HANDLE);
47         attest->qualifiedSigner.t.size =
48              TPM_HANDLE_Marshal(&signHandle, &buffer, &bufferSize);
49     }
50     else
51     {
52         // Certifying object qualified name
53         // if the scheme is anonymous, this is an empty buffer
54         if(CryptIsSchemeAnonymous(scheme->scheme))
55              attest->qualifiedSigner.t.size = 0;
56         else
57              ObjectGetQualifiedName(signHandle, &attest->qualifiedSigner);
58   }
59   // current clock in plain text
60   TimeFillInfo(&attest->clockInfo);
61   // Firmware version in plain text
62   attest->firmwareVersion = ((UINT64) gp.firmwareV1 << (sizeof(UINT32) * 8));
63   attest->firmwareVersion += gp.firmwareV2;
64   // Get the hierarchy of sign object. For NULL sign handle, the hierarchy
65   // will be TPM_RH_NULL
66   signHierarhcy = EntityGetHierarchy(signHandle);
67   if(signHierarhcy != TPM_RH_PLATFORM && signHierarhcy != TPM_RH_ENDORSEMENT)
68   {
69       // For sign object is not in platform or endorsement hierarchy,
70       // obfuscate the clock and firmwereVersion information
71       UINT64          obfuscation[2];
72       TPMI_ALG_HASH   hashAlg;
73         // Get hash algorithm
74         if(signHandle == TPM_RH_NULL || signHandle == TPM_RH_OWNER)
75         {
76              hashAlg = CONTEXT_INTEGRITY_HASH_ALG;
77         }
78         else
79         {
80              OBJECT          *signObject = NULL;
81              signObject = ObjectGet(signHandle);
82              hashAlg = signObject->publicArea.nameAlg;
83         }
84         KDFa(hashAlg, &gp.shProof.b, "OBFUSCATE",
85               &attest->qualifiedSigner.b, NULL, 128, (BYTE *)&obfuscation[0], NULL);
86         // Obfuscate data
87         attest->firmwareVersion += obfuscation[0];
88         attest->clockInfo.resetCount += (UINT32)(obfuscation[1] >> 32);
89         attest->clockInfo.restartCount += (UINT32)obfuscation[1];
90   }
91   // External data
92   if(CryptIsSchemeAnonymous(scheme->scheme))
93       attest->extraData.t.size = 0;
94   else
95   {
96       // If we move the data to the attestation structure, then we will not use
97       // it in the signing operation except as part of the signed data
98       attest->extraData = *data;
99       data->t.size = 0;
100   }
101   return TPM_RC_SUCCESS;
102}
103//
104//
105//          SignAttestInfo()
106//
107//     Sign a TPMS_ATTEST structure. If signHandle is TPM_RH_NULL, a null signature is returned.
108//
109//
110//
111//
112//      Error Returns                     Meaning
113//
114//      TPM_RC_ATTRIBUTES                 signHandle references not a signing key
115//      TPM_RC_SCHEME                     scheme is not compatible with signHandle type
116//      TPM_RC_VALUE                      digest generated for the given scheme is greater than the modulus of
117//                                        signHandle (for an RSA key); invalid commit status or failed to
118//                                        generate r value (for an ECC key)
119//
120TPM_RC
121SignAttestInfo(
122   TPMI_DH_OBJECT           signHandle,                //   IN: handle of sign object
123   TPMT_SIG_SCHEME         *scheme,                    //   IN: sign scheme
124   TPMS_ATTEST             *certifyInfo,               //   IN: the data to be signed
125   TPM2B_DATA              *qualifyingData,            //   IN: extra data for the signing proce
126   TPM2B_ATTEST            *attest,                    //   OUT: marshaled attest blob to be
127                                                       //       signed
128   TPMT_SIGNATURE          *signature                  //   OUT: signature
129   )
130{
131   TPM_RC                         result;
132   TPMI_ALG_HASH                  hashAlg;
133   BYTE                           *buffer;
134   INT32                          bufferSize;
135   HASH_STATE                     hashState;
136   TPM2B_DIGEST                   digest;
137   // Marshal TPMS_ATTEST structure for hash
138   buffer = attest->t.attestationData;
139   bufferSize = sizeof(TPMS_ATTEST);
140   attest->t.size = TPMS_ATTEST_Marshal(certifyInfo, &buffer, &bufferSize);
141   if(signHandle == TPM_RH_NULL)
142   {
143       signature->sigAlg = TPM_ALG_NULL;
144   }
145   else
146   {
147       // Attestation command may cause the orderlyState to be cleared due to
148       // the reporting of clock info. If this is the case, check if NV is
149       // available first
150       if(gp.orderlyState != SHUTDOWN_NONE)
151       {
152           // The command needs NV update. Check if NV is available.
153           // A TPM_RC_NV_UNAVAILABLE or TPM_RC_NV_RATE error may be returned at
154           // this point
155           result = NvIsAvailable();
156           if(result != TPM_RC_SUCCESS)
157               return result;
158       }
159         // Compute hash
160         hashAlg = scheme->details.any.hashAlg;
161         digest.t.size = CryptStartHash(hashAlg, &hashState);
162         CryptUpdateDigest(&hashState, attest->t.size, attest->t.attestationData);
163         CryptCompleteHash2B(&hashState, &digest.b);
164         // If there is qualifying data, need to rehash the the data
165         // hash(qualifyingData || hash(attestationData))
166         if(qualifyingData->t.size != 0)
167         {
168             CryptStartHash(hashAlg, &hashState);
169             CryptUpdateDigest(&hashState,
170                               qualifyingData->t.size,
171                               qualifyingData->t.buffer);
172             CryptUpdateDigest(&hashState, digest.t.size, digest.t.buffer);
173             CryptCompleteHash2B(&hashState, &digest.b);
174          }
175          // Sign the hash. A TPM_RC_VALUE, TPM_RC_SCHEME, or
176          // TPM_RC_ATTRIBUTES error may be returned at this point
177          return CryptSign(signHandle,
178                           scheme,
179                           &digest,
180                           signature);
181     }
182     return TPM_RC_SUCCESS;
183}
184