Vadim Bendebury | 5679752 | 2015-05-20 10:32:25 -0700 | [diff] [blame] | 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 | // |
| 25 | TPM_RC |
| 26 | FillInAttestInfo( |
| 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 | // For null sign handle, the QN is TPM_RH_NULL |
Vadim Bendebury | b86371b | 2015-05-27 18:16:19 -0700 | [diff] [blame] | 44 | buffer = attest->qualifiedSigner.t.buffer; |
Vadim Bendebury | 5679752 | 2015-05-20 10:32:25 -0700 | [diff] [blame] | 45 | attest->qualifiedSigner.t.size = |
| 46 | TPM_HANDLE_Marshal(&signHandle, &buffer, NULL); |
| 47 | } |
| 48 | else |
| 49 | { |
| 50 | // Certifying object qualified name |
| 51 | // if the scheme is anonymous, this is an empty buffer |
| 52 | if(CryptIsSchemeAnonymous(scheme->scheme)) |
| 53 | attest->qualifiedSigner.t.size = 0; |
| 54 | else |
| 55 | ObjectGetQualifiedName(signHandle, &attest->qualifiedSigner); |
| 56 | } |
| 57 | // current clock in plain text |
| 58 | TimeFillInfo(&attest->clockInfo); |
| 59 | // Firmware version in plain text |
| 60 | attest->firmwareVersion = ((UINT64) gp.firmwareV1 << (sizeof(UINT32) * 8)); |
| 61 | attest->firmwareVersion += gp.firmwareV2; |
| 62 | // Get the hierarchy of sign object. For NULL sign handle, the hierarchy |
| 63 | // will be TPM_RH_NULL |
| 64 | signHierarhcy = EntityGetHierarchy(signHandle); |
| 65 | if(signHierarhcy != TPM_RH_PLATFORM && signHierarhcy != TPM_RH_ENDORSEMENT) |
| 66 | { |
| 67 | // For sign object is not in platform or endorsement hierarchy, |
| 68 | // obfuscate the clock and firmwereVersion information |
| 69 | UINT64 obfuscation[2]; |
| 70 | TPMI_ALG_HASH hashAlg; |
| 71 | // Get hash algorithm |
| 72 | if(signHandle == TPM_RH_NULL || signHandle == TPM_RH_OWNER) |
| 73 | { |
| 74 | hashAlg = CONTEXT_INTEGRITY_HASH_ALG; |
| 75 | } |
| 76 | else |
| 77 | { |
| 78 | OBJECT *signObject = NULL; |
| 79 | signObject = ObjectGet(signHandle); |
| 80 | hashAlg = signObject->publicArea.nameAlg; |
| 81 | } |
| 82 | KDFa(hashAlg, &gp.shProof.b, "OBFUSCATE", |
| 83 | &attest->qualifiedSigner.b, NULL, 128, (BYTE *)&obfuscation[0], NULL); |
| 84 | // Obfuscate data |
| 85 | attest->firmwareVersion += obfuscation[0]; |
| 86 | attest->clockInfo.resetCount += (UINT32)(obfuscation[1] >> 32); |
| 87 | attest->clockInfo.restartCount += (UINT32)obfuscation[1]; |
| 88 | } |
| 89 | // External data |
| 90 | if(CryptIsSchemeAnonymous(scheme->scheme)) |
| 91 | attest->extraData.t.size = 0; |
| 92 | else |
| 93 | { |
| 94 | // If we move the data to the attestation structure, then we will not use |
| 95 | // it in the signing operation except as part of the signed data |
| 96 | attest->extraData = *data; |
| 97 | data->t.size = 0; |
| 98 | } |
| 99 | return TPM_RC_SUCCESS; |
| 100 | } |
| 101 | // |
| 102 | // |
| 103 | // SignAttestInfo() |
| 104 | // |
| 105 | // Sign a TPMS_ATTEST structure. If signHandle is TPM_RH_NULL, a null signature is returned. |
| 106 | // |
| 107 | // |
| 108 | // |
| 109 | // |
| 110 | // Error Returns Meaning |
| 111 | // |
| 112 | // TPM_RC_ATTRIBUTES signHandle references not a signing key |
| 113 | // TPM_RC_SCHEME scheme is not compatible with signHandle type |
| 114 | // TPM_RC_VALUE digest generated for the given scheme is greater than the modulus of |
| 115 | // signHandle (for an RSA key); invalid commit status or failed to |
| 116 | // generate r value (for an ECC key) |
| 117 | // |
| 118 | TPM_RC |
| 119 | SignAttestInfo( |
| 120 | TPMI_DH_OBJECT signHandle, // IN: handle of sign object |
| 121 | TPMT_SIG_SCHEME *scheme, // IN: sign scheme |
| 122 | TPMS_ATTEST *certifyInfo, // IN: the data to be signed |
| 123 | TPM2B_DATA *qualifyingData, // IN: extra data for the signing proce |
| 124 | TPM2B_ATTEST *attest, // OUT: marshaled attest blob to be |
| 125 | // signed |
| 126 | TPMT_SIGNATURE *signature // OUT: signature |
| 127 | ) |
| 128 | { |
| 129 | TPM_RC result; |
| 130 | TPMI_ALG_HASH hashAlg; |
| 131 | BYTE *buffer; |
| 132 | HASH_STATE hashState; |
| 133 | TPM2B_DIGEST digest; |
| 134 | // Marshal TPMS_ATTEST structure for hash |
Vadim Bendebury | b86371b | 2015-05-27 18:16:19 -0700 | [diff] [blame] | 135 | buffer = attest->t.buffer; |
Vadim Bendebury | 5679752 | 2015-05-20 10:32:25 -0700 | [diff] [blame] | 136 | attest->t.size = TPMS_ATTEST_Marshal(certifyInfo, &buffer, NULL); |
| 137 | if(signHandle == TPM_RH_NULL) |
| 138 | { |
| 139 | signature->sigAlg = TPM_ALG_NULL; |
| 140 | } |
| 141 | else |
| 142 | { |
| 143 | // Attestation command may cause the orderlyState to be cleared due to |
| 144 | // the reporting of clock info. If this is the case, check if NV is |
| 145 | // available first |
| 146 | if(gp.orderlyState != SHUTDOWN_NONE) |
| 147 | { |
| 148 | // The command needs NV update. Check if NV is available. |
| 149 | // A TPM_RC_NV_UNAVAILABLE or TPM_RC_NV_RATE error may be returned at |
| 150 | // this point |
| 151 | result = NvIsAvailable(); |
| 152 | if(result != TPM_RC_SUCCESS) |
| 153 | return result; |
| 154 | } |
| 155 | // Compute hash |
| 156 | hashAlg = scheme->details.any.hashAlg; |
| 157 | digest.t.size = CryptStartHash(hashAlg, &hashState); |
Vadim Bendebury | b86371b | 2015-05-27 18:16:19 -0700 | [diff] [blame] | 158 | CryptUpdateDigest(&hashState, attest->t.size, attest->t.buffer); |
Vadim Bendebury | 5679752 | 2015-05-20 10:32:25 -0700 | [diff] [blame] | 159 | CryptCompleteHash2B(&hashState, &digest.b); |
| 160 | // If there is qualifying data, need to rehash the the data |
| 161 | // hash(qualifyingData || hash(attestationData)) |
| 162 | if(qualifyingData->t.size != 0) |
| 163 | { |
| 164 | CryptStartHash(hashAlg, &hashState); |
| 165 | CryptUpdateDigest(&hashState, |
| 166 | qualifyingData->t.size, |
| 167 | qualifyingData->t.buffer); |
| 168 | CryptUpdateDigest(&hashState, digest.t.size, digest.t.buffer); |
| 169 | CryptCompleteHash2B(&hashState, &digest.b); |
| 170 | } |
| 171 | // Sign the hash. A TPM_RC_VALUE, TPM_RC_SCHEME, or |
| 172 | // TPM_RC_ATTRIBUTES error may be returned at this point |
| 173 | return CryptSign(signHandle, |
| 174 | scheme, |
| 175 | &digest, |
| 176 | signature); |
| 177 | } |
| 178 | return TPM_RC_SUCCESS; |
| 179 | } |