aboutsummaryrefslogtreecommitdiff
path: root/Attest_spt.c
blob: 7dc489cd9ddfbaa89356c514c204791c63b0dd2b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
// This file was extracted from the TCG Published
// Trusted Platform Module Library
// Part 4: Supporting Routines
// Family "2.0"
// Level 00 Revision 01.16
// October 30, 2014

#include "InternalRoutines.h"
#include "Attest_spt_fp.h"
//
//
//          Functions
//
//          FillInAttestInfo()
//
//     Fill in common fields of TPMS_ATTEST structure.
//
//     Error Returns                     Meaning
//
//     TPM_RC_KEY                        key referenced by signHandle is not a signing key
//     TPM_RC_SCHEME                     both scheme and key's default scheme are empty; or scheme is
//                                       empty while key's default scheme requires explicit input scheme (split
//                                       signing); or non-empty default key scheme differs from scheme
//
TPM_RC
FillInAttestInfo(
     TPMI_DH_OBJECT         signHandle,            //   IN: handle of signing object
     TPMT_SIG_SCHEME       *scheme,                //   IN/OUT: scheme to be used for signing
     TPM2B_DATA            *data,                  //   IN: qualifying data
     TPMS_ATTEST           *attest                 //   OUT: attest structure
     )
{
     TPM_RC                         result;
     TPMI_RH_HIERARCHY              signHierarhcy;
     result = CryptSelectSignScheme(signHandle, scheme);
     if(result != TPM_RC_SUCCESS)
         return result;
     // Magic number
     attest->magic = TPM_GENERATED_VALUE;
     if(signHandle == TPM_RH_NULL)
     {
         BYTE     *buffer;
         INT32     bufferSize;
         // For null sign handle, the QN is TPM_RH_NULL
         buffer = attest->qualifiedSigner.t.name;
         bufferSize = sizeof(TPM_HANDLE);
         attest->qualifiedSigner.t.size =
              TPM_HANDLE_Marshal(&signHandle, &buffer, &bufferSize);
     }
     else
     {
         // Certifying object qualified name
         // if the scheme is anonymous, this is an empty buffer
         if(CryptIsSchemeAnonymous(scheme->scheme))
              attest->qualifiedSigner.t.size = 0;
         else
              ObjectGetQualifiedName(signHandle, &attest->qualifiedSigner);
   }
   // current clock in plain text
   TimeFillInfo(&attest->clockInfo);
   // Firmware version in plain text
   attest->firmwareVersion = ((UINT64) gp.firmwareV1 << (sizeof(UINT32) * 8));
   attest->firmwareVersion += gp.firmwareV2;
   // Get the hierarchy of sign object. For NULL sign handle, the hierarchy
   // will be TPM_RH_NULL
   signHierarhcy = EntityGetHierarchy(signHandle);
   if(signHierarhcy != TPM_RH_PLATFORM && signHierarhcy != TPM_RH_ENDORSEMENT)
   {
       // For sign object is not in platform or endorsement hierarchy,
       // obfuscate the clock and firmwereVersion information
       UINT64          obfuscation[2];
       TPMI_ALG_HASH   hashAlg;
         // Get hash algorithm
         if(signHandle == TPM_RH_NULL || signHandle == TPM_RH_OWNER)
         {
              hashAlg = CONTEXT_INTEGRITY_HASH_ALG;
         }
         else
         {
              OBJECT          *signObject = NULL;
              signObject = ObjectGet(signHandle);
              hashAlg = signObject->publicArea.nameAlg;
         }
         KDFa(hashAlg, &gp.shProof.b, "OBFUSCATE",
               &attest->qualifiedSigner.b, NULL, 128, (BYTE *)&obfuscation[0], NULL);
         // Obfuscate data
         attest->firmwareVersion += obfuscation[0];
         attest->clockInfo.resetCount += (UINT32)(obfuscation[1] >> 32);
         attest->clockInfo.restartCount += (UINT32)obfuscation[1];
   }
   // External data
   if(CryptIsSchemeAnonymous(scheme->scheme))
       attest->extraData.t.size = 0;
   else
   {
       // If we move the data to the attestation structure, then we will not use
       // it in the signing operation except as part of the signed data
       attest->extraData = *data;
       data->t.size = 0;
   }
   return TPM_RC_SUCCESS;
}
//
//
//          SignAttestInfo()
//
//     Sign a TPMS_ATTEST structure. If signHandle is TPM_RH_NULL, a null signature is returned.
//
//
//
//
//      Error Returns                     Meaning
//
//      TPM_RC_ATTRIBUTES                 signHandle references not a signing key
//      TPM_RC_SCHEME                     scheme is not compatible with signHandle type
//      TPM_RC_VALUE                      digest generated for the given scheme is greater than the modulus of
//                                        signHandle (for an RSA key); invalid commit status or failed to
//                                        generate r value (for an ECC key)
//
TPM_RC
SignAttestInfo(
   TPMI_DH_OBJECT           signHandle,                //   IN: handle of sign object
   TPMT_SIG_SCHEME         *scheme,                    //   IN: sign scheme
   TPMS_ATTEST             *certifyInfo,               //   IN: the data to be signed
   TPM2B_DATA              *qualifyingData,            //   IN: extra data for the signing proce
   TPM2B_ATTEST            *attest,                    //   OUT: marshaled attest blob to be
                                                       //       signed
   TPMT_SIGNATURE          *signature                  //   OUT: signature
   )
{
   TPM_RC                         result;
   TPMI_ALG_HASH                  hashAlg;
   BYTE                           *buffer;
   INT32                          bufferSize;
   HASH_STATE                     hashState;
   TPM2B_DIGEST                   digest;
   // Marshal TPMS_ATTEST structure for hash
   buffer = attest->t.attestationData;
   bufferSize = sizeof(TPMS_ATTEST);
   attest->t.size = TPMS_ATTEST_Marshal(certifyInfo, &buffer, &bufferSize);
   if(signHandle == TPM_RH_NULL)
   {
       signature->sigAlg = TPM_ALG_NULL;
   }
   else
   {
       // Attestation command may cause the orderlyState to be cleared due to
       // the reporting of clock info. If this is the case, check if NV is
       // available first
       if(gp.orderlyState != SHUTDOWN_NONE)
       {
           // The command needs NV update. Check if NV is available.
           // A TPM_RC_NV_UNAVAILABLE or TPM_RC_NV_RATE error may be returned at
           // this point
           result = NvIsAvailable();
           if(result != TPM_RC_SUCCESS)
               return result;
       }
         // Compute hash
         hashAlg = scheme->details.any.hashAlg;
         digest.t.size = CryptStartHash(hashAlg, &hashState);
         CryptUpdateDigest(&hashState, attest->t.size, attest->t.attestationData);
         CryptCompleteHash2B(&hashState, &digest.b);
         // If there is qualifying data, need to rehash the the data
         // hash(qualifyingData || hash(attestationData))
         if(qualifyingData->t.size != 0)
         {
             CryptStartHash(hashAlg, &hashState);
             CryptUpdateDigest(&hashState,
                               qualifyingData->t.size,
                               qualifyingData->t.buffer);
             CryptUpdateDigest(&hashState, digest.t.size, digest.t.buffer);
             CryptCompleteHash2B(&hashState, &digest.b);
          }
          // Sign the hash. A TPM_RC_VALUE, TPM_RC_SCHEME, or
          // TPM_RC_ATTRIBUTES error may be returned at this point
          return CryptSign(signHandle,
                           scheme,
                           &digest,
                           signature);
     }
     return TPM_RC_SUCCESS;
}