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 | |
Vadim Bendebury | 34f0a9a | 2015-05-29 12:24:59 -0700 | [diff] [blame] | 8 | #include <string.h> |
| 9 | |
Vadim Bendebury | 5679752 | 2015-05-20 10:32:25 -0700 | [diff] [blame] | 10 | #include "OsslCryptoEngine.h" |
| 11 | #include "CpriHashData.c" |
Vadim Sukhomlinov | 6a2d0e0 | 2019-08-01 18:18:56 -0700 | [diff] [blame] | 12 | #if OPENSSL_VERSION_NUMBER < 0x10100000L |
Vadim Bendebury | 5679752 | 2015-05-20 10:32:25 -0700 | [diff] [blame] | 13 | // |
| 14 | // Temporary aliasing of SM3 to SHA256 until SM3 is available |
| 15 | // |
Vadim Sukhomlinov | 6a2d0e0 | 2019-08-01 18:18:56 -0700 | [diff] [blame] | 16 | #define EVP_sm3 EVP_sha256 |
| 17 | |
| 18 | static void *OPENSSL_zalloc(size_t num) |
| 19 | { |
| 20 | void *ret = OPENSSL_malloc(num); |
| 21 | if (ret != NULL) |
| 22 | memset(ret, 0, num); |
| 23 | return ret; |
| 24 | } |
| 25 | |
| 26 | static EVP_MD_CTX *EVP_MD_CTX_new(void) |
| 27 | { |
| 28 | return OPENSSL_zalloc(sizeof(EVP_MD_CTX)); |
| 29 | } |
| 30 | |
| 31 | static void EVP_MD_CTX_free(EVP_MD_CTX *ctx) |
| 32 | { |
| 33 | EVP_MD_CTX_cleanup(ctx); |
| 34 | OPENSSL_free(ctx); |
| 35 | } |
| 36 | #endif |
Vadim Bendebury | 5679752 | 2015-05-20 10:32:25 -0700 | [diff] [blame] | 37 | // |
| 38 | // |
| 39 | // Static Functions |
| 40 | // |
| 41 | // GetHashServer() |
| 42 | // |
| 43 | // This function returns the address of the hash server function |
| 44 | // |
| 45 | static EVP_MD * |
| 46 | GetHashServer( |
| 47 | TPM_ALG_ID hashAlg |
| 48 | ) |
| 49 | { |
| 50 | switch (hashAlg) |
| 51 | { |
| 52 | #ifdef TPM_ALG_SHA1 |
| 53 | case TPM_ALG_SHA1: |
| 54 | return (EVP_MD *)EVP_sha1(); |
| 55 | break; |
| 56 | #endif |
| 57 | #ifdef TPM_ALG_SHA256 |
| 58 | case TPM_ALG_SHA256: |
| 59 | return (EVP_MD *)EVP_sha256(); |
| 60 | break; |
| 61 | #endif |
| 62 | #ifdef TPM_ALG_SHA384 |
| 63 | case TPM_ALG_SHA384: |
| 64 | return (EVP_MD *)EVP_sha384(); |
| 65 | break; |
| 66 | #endif |
| 67 | #ifdef TPM_ALG_SHA512 |
| 68 | case TPM_ALG_SHA512: |
| 69 | return (EVP_MD *)EVP_sha512(); |
| 70 | break; |
| 71 | #endif |
| 72 | #ifdef TPM_ALG_SM3_256 |
| 73 | case TPM_ALG_SM3_256: |
Vadim Sukhomlinov | 6a2d0e0 | 2019-08-01 18:18:56 -0700 | [diff] [blame] | 74 | return (EVP_MD *)EVP_sm3(); // OpenSSL 1.1 introduced this function |
Vadim Bendebury | 5679752 | 2015-05-20 10:32:25 -0700 | [diff] [blame] | 75 | break; |
| 76 | #endif |
| 77 | case TPM_ALG_NULL: |
| 78 | return NULL; |
| 79 | default: |
| 80 | FAIL(FATAL_ERROR_INTERNAL); |
| 81 | } |
Vadim Bendebury | 34f0a9a | 2015-05-29 12:24:59 -0700 | [diff] [blame] | 82 | return NULL; // Never reached. |
Vadim Bendebury | 5679752 | 2015-05-20 10:32:25 -0700 | [diff] [blame] | 83 | } |
Vadim Sukhomlinov | 6a2d0e0 | 2019-08-01 18:18:56 -0700 | [diff] [blame] | 84 | |
Vadim Bendebury | 5679752 | 2015-05-20 10:32:25 -0700 | [diff] [blame] | 85 | // |
| 86 | // |
| 87 | // GetHashInfoPointer() |
| 88 | // |
| 89 | // This function returns a pointer to the hash info for the algorithm. If the algorithm is not supported, function |
| 90 | // returns a pointer to the data block associated with TPM_ALG_NULL. |
| 91 | // |
| 92 | static const HASH_INFO * |
| 93 | GetHashInfoPointer( |
| 94 | TPM_ALG_ID hashAlg |
| 95 | ) |
| 96 | { |
| 97 | UINT32 i, tableSize; |
| 98 | // Get the table size of g_hashData |
| 99 | tableSize = sizeof(g_hashData) / sizeof(g_hashData[0]); |
| 100 | for(i = 0; i < tableSize - 1; i++) |
| 101 | { |
| 102 | if(g_hashData[i].alg == hashAlg) |
| 103 | return &g_hashData[i]; |
| 104 | } |
| 105 | return &g_hashData[tableSize-1]; |
| 106 | } |
| 107 | // |
| 108 | // |
| 109 | // Hash Functions |
| 110 | // |
| 111 | // _cpri__HashStartup() |
| 112 | // |
| 113 | // Function that is called to initialize the hash service. In this implementation, this function does nothing but |
| 114 | // it is called by the CryptUtilStartup() function and must be present. |
| 115 | // |
| 116 | LIB_EXPORT BOOL |
| 117 | _cpri__HashStartup( |
| 118 | void |
| 119 | ) |
| 120 | { |
Vadim Bendebury | 5679752 | 2015-05-20 10:32:25 -0700 | [diff] [blame] | 121 | return TRUE; |
| 122 | } |
| 123 | // |
| 124 | // |
| 125 | // _cpri__GetHashAlgByIndex() |
| 126 | // |
| 127 | // This function is used to iterate through the hashes. TPM_ALG_NULL is returned for all indexes that are |
| 128 | // not valid hashes. If the TPM implements 3 hashes, then an index value of 0 will return the first |
| 129 | // implemented hash and and index of 2 will return the last. All other index values will return |
| 130 | // TPM_ALG_NULL. |
| 131 | // |
| 132 | // |
| 133 | // |
| 134 | // |
| 135 | // Return Value Meaning |
| 136 | // |
| 137 | // TPM_ALG_xxx() a hash algorithm |
| 138 | // TPM_ALG_NULL this can be used as a stop value |
| 139 | // |
| 140 | LIB_EXPORT TPM_ALG_ID |
| 141 | _cpri__GetHashAlgByIndex( |
| 142 | UINT32 index // IN: the index |
| 143 | ) |
| 144 | { |
| 145 | if(index >= HASH_COUNT) |
| 146 | return TPM_ALG_NULL; |
| 147 | return g_hashData[index].alg; |
| 148 | } |
| 149 | // |
| 150 | // |
| 151 | // _cpri__GetHashBlockSize() |
| 152 | // |
| 153 | // Returns the size of the block used for the hash |
| 154 | // |
| 155 | // Return Value Meaning |
| 156 | // |
| 157 | // <0 the algorithm is not a supported hash |
| 158 | // >= the digest size (0 for TPM_ALG_NULL) |
| 159 | // |
| 160 | LIB_EXPORT UINT16 |
| 161 | _cpri__GetHashBlockSize( |
| 162 | TPM_ALG_ID hashAlg // IN: hash algorithm to look up |
| 163 | ) |
| 164 | { |
| 165 | return GetHashInfoPointer(hashAlg)->blockSize; |
| 166 | } |
| 167 | // |
| 168 | // |
| 169 | // _cpri__GetHashDER |
| 170 | // |
| 171 | // This function returns a pointer to the DER string for the algorithm and indicates its size. |
| 172 | // |
| 173 | LIB_EXPORT UINT16 |
| 174 | _cpri__GetHashDER( |
| 175 | TPM_ALG_ID hashAlg, // IN: the algorithm to look up |
| 176 | const BYTE **p |
| 177 | ) |
| 178 | { |
| 179 | const HASH_INFO *q; |
| 180 | q = GetHashInfoPointer(hashAlg); |
| 181 | *p = &q->der[0]; |
| 182 | return q->derSize; |
| 183 | } |
| 184 | // |
| 185 | // |
| 186 | // _cpri__GetDigestSize() |
| 187 | // |
| 188 | // Gets the digest size of the algorithm. The algorithm is required to be supported. |
| 189 | // |
| 190 | // Return Value Meaning |
| 191 | // |
| 192 | // =0 the digest size for TPM_ALG_NULL |
| 193 | // >0 the digest size of a hash algorithm |
| 194 | // |
| 195 | LIB_EXPORT UINT16 |
| 196 | _cpri__GetDigestSize( |
| 197 | TPM_ALG_ID hashAlg // IN: hash algorithm to look up |
| 198 | ) |
| 199 | { |
| 200 | return GetHashInfoPointer(hashAlg)->digestSize; |
| 201 | } |
| 202 | // |
| 203 | // |
| 204 | // _cpri__GetContextAlg() |
| 205 | // |
| 206 | // This function returns the algorithm associated with a hash context |
| 207 | // |
| 208 | LIB_EXPORT TPM_ALG_ID |
| 209 | _cpri__GetContextAlg( |
| 210 | CPRI_HASH_STATE *hashState // IN: the hash context |
| 211 | ) |
| 212 | { |
| 213 | return hashState->hashAlg; |
| 214 | } |
| 215 | // |
| 216 | // |
| 217 | // _cpri__CopyHashState |
| 218 | // |
| 219 | // This function is used to clone a CPRI_HASH_STATE. The return value is the size of the state. |
| 220 | // |
| 221 | LIB_EXPORT UINT16 |
| 222 | _cpri__CopyHashState ( |
| 223 | CPRI_HASH_STATE *out, // OUT: destination of the state |
| 224 | CPRI_HASH_STATE *in // IN: source of the state |
| 225 | ) |
| 226 | { |
Vadim Sukhomlinov | 6a2d0e0 | 2019-08-01 18:18:56 -0700 | [diff] [blame] | 227 | EVP_MD_CTX *in_ctx = *(EVP_MD_CTX **)&in->state; |
| 228 | EVP_MD_CTX *out_ctx; |
| 229 | pAssert(sizeof(out->state) >= sizeof(EVP_MD_CTX *)); |
| 230 | if((out_ctx = EVP_MD_CTX_new()) == NULL) |
| 231 | FAIL(FATAL_ERROR_INTERNAL); |
| 232 | if(!EVP_MD_CTX_copy_ex(out_ctx, in_ctx)) |
| 233 | { |
| 234 | EVP_MD_CTX_free(out_ctx); |
| 235 | return 0; |
| 236 | } |
| 237 | *(EVP_MD_CTX**)&out->state = out_ctx; |
Vadim Bendebury | 5679752 | 2015-05-20 10:32:25 -0700 | [diff] [blame] | 238 | out->hashAlg = in->hashAlg; |
Vadim Sukhomlinov | 6a2d0e0 | 2019-08-01 18:18:56 -0700 | [diff] [blame] | 239 | return sizeof(EVP_MD_CTX *); |
Vadim Bendebury | 5679752 | 2015-05-20 10:32:25 -0700 | [diff] [blame] | 240 | } |
Vadim Sukhomlinov | 6a2d0e0 | 2019-08-01 18:18:56 -0700 | [diff] [blame] | 241 | |
Vadim Bendebury | 5679752 | 2015-05-20 10:32:25 -0700 | [diff] [blame] | 242 | // |
| 243 | // |
| 244 | // _cpri__StartHash() |
| 245 | // |
| 246 | // Functions starts a hash stack Start a hash stack and returns the digest size. As a side effect, the value of |
| 247 | // stateSize in hashState is updated to indicate the number of bytes of state that were saved. This function |
| 248 | // calls GetHashServer() and that function will put the TPM into failure mode if the hash algorithm is not |
| 249 | // supported. |
| 250 | // |
| 251 | // Return Value Meaning |
| 252 | // |
| 253 | // 0 hash is TPM_ALG_NULL |
| 254 | // >0 digest size |
Vadim Bendebury | 5679752 | 2015-05-20 10:32:25 -0700 | [diff] [blame] | 255 | LIB_EXPORT UINT16 |
| 256 | _cpri__StartHash( |
| 257 | TPM_ALG_ID hashAlg, // IN: hash algorithm |
| 258 | BOOL sequence, // IN: TRUE if the state should be saved |
| 259 | CPRI_HASH_STATE *hashState // OUT: the state of hash stack. |
| 260 | ) |
| 261 | { |
Vadim Sukhomlinov | 6a2d0e0 | 2019-08-01 18:18:56 -0700 | [diff] [blame] | 262 | EVP_MD_CTX *context = *(EVP_MD_CTX **)&hashState->state; |
| 263 | EVP_MD *evpmdAlgorithm = NULL; |
| 264 | pAssert(sizeof(hashState->state) >= sizeof(EVP_MD_CTX *)); |
| 265 | evpmdAlgorithm = GetHashServer(hashAlg); |
| 266 | if(evpmdAlgorithm == NULL) |
| 267 | return 0; |
| 268 | if((context = EVP_MD_CTX_new()) == NULL) |
| 269 | FAIL(FATAL_ERROR_INTERNAL); |
| 270 | *(EVP_MD_CTX**)&hashState->state = context; |
| 271 | hashState->hashAlg = hashAlg; |
| 272 | if(EVP_DigestInit_ex(context, evpmdAlgorithm, NULL) != 1) |
| 273 | FAIL(FATAL_ERROR_INTERNAL); |
| 274 | return (CRYPT_RESULT)EVP_MD_CTX_size(context); |
Vadim Bendebury | 5679752 | 2015-05-20 10:32:25 -0700 | [diff] [blame] | 275 | } |
| 276 | // |
| 277 | // |
| 278 | // _cpri__UpdateHash() |
| 279 | // |
| 280 | // Add data to a hash or HMAC stack. |
| 281 | // |
| 282 | LIB_EXPORT void |
| 283 | _cpri__UpdateHash( |
| 284 | CPRI_HASH_STATE *hashState, // IN: the hash context information |
| 285 | UINT32 dataSize, // IN: the size of data to be added to the |
| 286 | // digest |
| 287 | BYTE *data // IN: data to be hashed |
| 288 | ) |
| 289 | { |
Vadim Sukhomlinov | 6a2d0e0 | 2019-08-01 18:18:56 -0700 | [diff] [blame] | 290 | EVP_MD_CTX *context = *(EVP_MD_CTX **)&hashState->state; |
Vadim Bendebury | 5679752 | 2015-05-20 10:32:25 -0700 | [diff] [blame] | 291 | // If there is no context, return |
Vadim Sukhomlinov | 6a2d0e0 | 2019-08-01 18:18:56 -0700 | [diff] [blame] | 292 | if(context == NULL) |
Vadim Bendebury | 5679752 | 2015-05-20 10:32:25 -0700 | [diff] [blame] | 293 | return; |
Vadim Bendebury | 5679752 | 2015-05-20 10:32:25 -0700 | [diff] [blame] | 294 | if(EVP_DigestUpdate(context, data, dataSize) != 1) |
| 295 | FAIL(FATAL_ERROR_INTERNAL); |
Vadim Bendebury | 5679752 | 2015-05-20 10:32:25 -0700 | [diff] [blame] | 296 | return; |
| 297 | } |
| 298 | // |
| 299 | // |
| 300 | // _cpri__CompleteHash() |
| 301 | // |
| 302 | // Complete a hash or HMAC computation. This function will place the smaller of digestSize or the size of |
| 303 | // the digest in dOut. The number of bytes in the placed in the buffer is returned. If there is a failure, the |
| 304 | // returned value is <= 0. |
| 305 | // |
| 306 | // Return Value Meaning |
| 307 | // |
| 308 | // 0 no data returned |
| 309 | // >0 the number of bytes in the digest |
| 310 | // |
| 311 | LIB_EXPORT UINT16 |
| 312 | _cpri__CompleteHash( |
| 313 | CPRI_HASH_STATE *hashState, // IN: the state of hash stack |
| 314 | UINT32 dOutSize, // IN: size of digest buffer |
| 315 | BYTE *dOut // OUT: hash digest |
| 316 | ) |
| 317 | { |
Vadim Sukhomlinov | 6a2d0e0 | 2019-08-01 18:18:56 -0700 | [diff] [blame] | 318 | EVP_MD_CTX *context = *(EVP_MD_CTX **)&hashState->state; |
Vadim Bendebury | 5679752 | 2015-05-20 10:32:25 -0700 | [diff] [blame] | 319 | UINT16 retVal; |
| 320 | int hLen; |
Vadim Sukhomlinov | 6a2d0e0 | 2019-08-01 18:18:56 -0700 | [diff] [blame] | 321 | BYTE temp[EVP_MAX_MD_SIZE]; |
Vadim Bendebury | 5679752 | 2015-05-20 10:32:25 -0700 | [diff] [blame] | 322 | BYTE *rBuffer = dOut; |
Vadim Sukhomlinov | 6a2d0e0 | 2019-08-01 18:18:56 -0700 | [diff] [blame] | 323 | if(context == NULL) |
Vadim Bendebury | 5679752 | 2015-05-20 10:32:25 -0700 | [diff] [blame] | 324 | return 0; |
Vadim Bendebury | 5679752 | 2015-05-20 10:32:25 -0700 | [diff] [blame] | 325 | hLen = EVP_MD_CTX_size(context); |
| 326 | if((unsigned)hLen > dOutSize) |
| 327 | rBuffer = temp; |
| 328 | if(EVP_DigestFinal_ex(context, rBuffer, NULL) == 1) |
| 329 | { |
| 330 | if(rBuffer != dOut) |
| 331 | { |
| 332 | if(dOut != NULL) |
| 333 | { |
| 334 | memcpy(dOut, temp, dOutSize); |
| 335 | } |
| 336 | retVal = (UINT16)dOutSize; |
| 337 | } |
| 338 | else |
| 339 | { |
| 340 | retVal = (UINT16)hLen; |
| 341 | } |
Vadim Bendebury | 5679752 | 2015-05-20 10:32:25 -0700 | [diff] [blame] | 342 | } |
| 343 | else |
| 344 | { |
| 345 | retVal = 0; // Indicate that no data is returned |
| 346 | } |
Vadim Sukhomlinov | 6a2d0e0 | 2019-08-01 18:18:56 -0700 | [diff] [blame] | 347 | |
| 348 | EVP_MD_CTX_free(context); |
| 349 | *(EVP_MD_CTX **)&hashState->state = NULL; |
Vadim Bendebury | 5679752 | 2015-05-20 10:32:25 -0700 | [diff] [blame] | 350 | return retVal; |
| 351 | } |
| 352 | // |
| 353 | // |
| 354 | // _cpri__ImportExportHashState() |
| 355 | // |
| 356 | // This function is used to import or export the hash state. This function would be called to export state when |
| 357 | // a sequence object was being prepared for export |
| 358 | // |
| 359 | LIB_EXPORT void |
| 360 | _cpri__ImportExportHashState( |
| 361 | CPRI_HASH_STATE *osslFmt, // IN/OUT: the hash state formated for use |
| 362 | // by openSSL |
| 363 | EXPORT_HASH_STATE *externalFmt, // IN/OUT: the exported hash state |
| 364 | IMPORT_EXPORT direction // |
| 365 | ) |
| 366 | { |
| 367 | UNREFERENCED_PARAMETER(direction); |
| 368 | UNREFERENCED_PARAMETER(externalFmt); |
| 369 | UNREFERENCED_PARAMETER(osslFmt); |
| 370 | return; |
| 371 | #if 0 |
| 372 | if(direction == IMPORT_STATE) |
| 373 | { |
| 374 | // don't have the import export functions yet so just copy |
| 375 | _cpri__CopyHashState(osslFmt, (CPRI_HASH_STATE *)externalFmt); |
| 376 | } |
| 377 | else |
| 378 | { |
| 379 | _cpri__CopyHashState((CPRI_HASH_STATE *)externalFmt, osslFmt); |
| 380 | } |
| 381 | #endif |
| 382 | } |
| 383 | // |
| 384 | // |
| 385 | // |
| 386 | // _cpri__HashBlock() |
| 387 | // |
| 388 | // Start a hash, hash a single block, update digest and return the size of the results. |
| 389 | // The digestSize parameter can be smaller than the digest. If so, only the more significant bytes are |
| 390 | // returned. |
| 391 | // |
| 392 | // Return Value Meaning |
| 393 | // |
| 394 | // >= 0 number of bytes in digest (may be zero) |
| 395 | // |
| 396 | LIB_EXPORT UINT16 |
| 397 | _cpri__HashBlock( |
| 398 | TPM_ALG_ID hashAlg, // IN: The hash algorithm |
| 399 | UINT32 dataSize, // IN: size of buffer to hash |
| 400 | BYTE *data, // IN: the buffer to hash |
| 401 | UINT32 digestSize, // IN: size of the digest buffer |
| 402 | BYTE *digest // OUT: hash digest |
| 403 | ) |
| 404 | { |
Vadim Sukhomlinov | 6a2d0e0 | 2019-08-01 18:18:56 -0700 | [diff] [blame] | 405 | EVP_MD_CTX *hashContext; |
Vadim Bendebury | 5679752 | 2015-05-20 10:32:25 -0700 | [diff] [blame] | 406 | EVP_MD *hashServer = NULL; |
| 407 | UINT16 retVal = 0; |
Vadim Sukhomlinov | 6a2d0e0 | 2019-08-01 18:18:56 -0700 | [diff] [blame] | 408 | BYTE b[EVP_MAX_MD_SIZE]; // temp buffer in case digestSize not |
Vadim Bendebury | 5679752 | 2015-05-20 10:32:25 -0700 | [diff] [blame] | 409 | // a full digest |
| 410 | unsigned int dSize = _cpri__GetDigestSize(hashAlg); |
| 411 | // If there is no digest to compute return |
| 412 | if(dSize == 0) |
| 413 | return 0; |
Vadim Sukhomlinov | 6a2d0e0 | 2019-08-01 18:18:56 -0700 | [diff] [blame] | 414 | if ((hashContext = EVP_MD_CTX_new()) == NULL) |
| 415 | FAIL(FATAL_ERROR_INTERNAL); |
Vadim Bendebury | 5679752 | 2015-05-20 10:32:25 -0700 | [diff] [blame] | 416 | hashServer = GetHashServer(hashAlg); // Find the hash server |
| 417 | // It is an error if the digest size is non-zero but there is no server |
| 418 | if( (hashServer == NULL) |
Vadim Sukhomlinov | 6a2d0e0 | 2019-08-01 18:18:56 -0700 | [diff] [blame] | 419 | || (EVP_DigestInit_ex(hashContext, hashServer, NULL) != 1) |
| 420 | || (EVP_DigestUpdate(hashContext, data, dataSize) != 1)) |
Vadim Bendebury | 5679752 | 2015-05-20 10:32:25 -0700 | [diff] [blame] | 421 | FAIL(FATAL_ERROR_INTERNAL); |
| 422 | else |
| 423 | { |
| 424 | // If the size of the digest produced (dSize) is larger than the available |
| 425 | // buffer (digestSize), then put the digest in a temp buffer and only copy |
| 426 | // the most significant part into the available buffer. |
| 427 | if(dSize > digestSize) |
| 428 | { |
Vadim Sukhomlinov | 6a2d0e0 | 2019-08-01 18:18:56 -0700 | [diff] [blame] | 429 | if(EVP_DigestFinal_ex(hashContext, b, &dSize) != 1) |
Vadim Bendebury | 5679752 | 2015-05-20 10:32:25 -0700 | [diff] [blame] | 430 | FAIL(FATAL_ERROR_INTERNAL); |
| 431 | memcpy(digest, b, digestSize); |
| 432 | retVal = (UINT16)digestSize; |
| 433 | } |
| 434 | else |
| 435 | { |
Vadim Sukhomlinov | 6a2d0e0 | 2019-08-01 18:18:56 -0700 | [diff] [blame] | 436 | if((EVP_DigestFinal_ex(hashContext, digest, &dSize)) != 1) |
Vadim Bendebury | 5679752 | 2015-05-20 10:32:25 -0700 | [diff] [blame] | 437 | FAIL(FATAL_ERROR_INTERNAL); |
| 438 | retVal = (UINT16) dSize; |
| 439 | } |
| 440 | } |
Vadim Sukhomlinov | 6a2d0e0 | 2019-08-01 18:18:56 -0700 | [diff] [blame] | 441 | EVP_MD_CTX_free(hashContext); |
Vadim Bendebury | 5679752 | 2015-05-20 10:32:25 -0700 | [diff] [blame] | 442 | return retVal; |
| 443 | } |
| 444 | // |
| 445 | // |
| 446 | // |
| 447 | // HMAC Functions |
| 448 | // |
| 449 | // _cpri__StartHMAC |
| 450 | // |
| 451 | // This function is used to start an HMAC using a temp hash context. The function does the initialization of |
| 452 | // the hash with the HMAC key XOR iPad and updates the HMAC key XOR oPad. |
| 453 | // The function returns the number of bytes in a digest produced by hashAlg. |
| 454 | // |
| 455 | // Return Value Meaning |
| 456 | // |
| 457 | // >= 0 number of bytes in digest produced by hashAlg (may be zero) |
| 458 | // |
| 459 | LIB_EXPORT UINT16 |
| 460 | _cpri__StartHMAC( |
| 461 | TPM_ALG_ID hashAlg, // IN: the algorithm to use |
| 462 | BOOL sequence, // IN: indicates if the state should be |
| 463 | // saved |
| 464 | CPRI_HASH_STATE *state, // IN/OUT: the state buffer |
| 465 | UINT16 keySize, // IN: the size of the HMAC key |
| 466 | BYTE *key, // IN: the HMAC key |
| 467 | TPM2B *oPadKey // OUT: the key prepared for the oPad round |
| 468 | ) |
| 469 | { |
Vadim Sukhomlinov | 6a2d0e0 | 2019-08-01 18:18:56 -0700 | [diff] [blame] | 470 | CPRI_HASH_STATE localState = {}; |
Vadim Bendebury | 5679752 | 2015-05-20 10:32:25 -0700 | [diff] [blame] | 471 | UINT16 blockSize = _cpri__GetHashBlockSize(hashAlg); |
| 472 | UINT16 digestSize; |
| 473 | BYTE *pb; // temp pointer |
| 474 | UINT32 i; |
Vadim Sukhomlinov | 6a2d0e0 | 2019-08-01 18:18:56 -0700 | [diff] [blame] | 475 | |
Vadim Bendebury | 5679752 | 2015-05-20 10:32:25 -0700 | [diff] [blame] | 476 | // If the key size is larger than the block size, then the hash of the key |
| 477 | // is used as the key |
| 478 | if(keySize > blockSize) |
| 479 | { |
| 480 | // large key so digest |
| 481 | if((digestSize = _cpri__StartHash(hashAlg, FALSE, &localState)) == 0) |
| 482 | return 0; |
| 483 | _cpri__UpdateHash(&localState, keySize, key); |
| 484 | _cpri__CompleteHash(&localState, digestSize, oPadKey->buffer); |
| 485 | oPadKey->size = digestSize; |
| 486 | } |
| 487 | else |
| 488 | { |
| 489 | // key size is ok |
| 490 | memcpy(oPadKey->buffer, key, keySize); |
| 491 | oPadKey->size = keySize; |
| 492 | } |
| 493 | // XOR the key with iPad (0x36) |
| 494 | pb = oPadKey->buffer; |
| 495 | for(i = oPadKey->size; i > 0; i--) |
| 496 | *pb++ ^= 0x36; |
| 497 | // if the keySize is smaller than a block, fill the rest with 0x36 |
| 498 | for(i = blockSize - oPadKey->size; i > 0; i--) |
| 499 | *pb++ = 0x36; |
| 500 | // Increase the oPadSize to a full block |
| 501 | oPadKey->size = blockSize; |
| 502 | // Start a new hash with the HMAC key |
| 503 | // This will go in the caller's state structure and may be a sequence or not |
| 504 | if((digestSize = _cpri__StartHash(hashAlg, sequence, state)) > 0) |
| 505 | { |
| 506 | _cpri__UpdateHash(state, oPadKey->size, oPadKey->buffer); |
| 507 | // XOR the key block with 0x5c ^ 0x36 |
| 508 | for(pb = oPadKey->buffer, i = blockSize; i > 0; i--) |
| 509 | *pb++ ^= (0x5c ^ 0x36); |
| 510 | } |
| 511 | return digestSize; |
| 512 | } |
| 513 | // |
| 514 | // |
| 515 | // _cpri_CompleteHMAC() |
| 516 | // |
| 517 | // This function is called to complete an HMAC. It will finish the current digest, and start a new digest. It will |
| 518 | // then add the oPadKey and the completed digest and return the results in dOut. It will not return more than |
| 519 | // dOutSize bytes. |
| 520 | // |
| 521 | // Return Value Meaning |
| 522 | // |
| 523 | // >= 0 number of bytes in dOut (may be zero) |
| 524 | // |
| 525 | LIB_EXPORT UINT16 |
| 526 | _cpri__CompleteHMAC( |
| 527 | CPRI_HASH_STATE *hashState, // IN: the state of hash stack |
| 528 | TPM2B *oPadKey, // IN: the HMAC key in oPad format |
| 529 | UINT32 dOutSize, // IN: size of digest buffer |
| 530 | BYTE *dOut // OUT: hash digest |
| 531 | ) |
| 532 | { |
| 533 | BYTE digest[MAX_DIGEST_SIZE]; |
| 534 | CPRI_HASH_STATE *state = (CPRI_HASH_STATE *)hashState; |
Vadim Sukhomlinov | 6a2d0e0 | 2019-08-01 18:18:56 -0700 | [diff] [blame] | 535 | CPRI_HASH_STATE localState = {}; |
Vadim Bendebury | 5679752 | 2015-05-20 10:32:25 -0700 | [diff] [blame] | 536 | UINT16 digestSize = _cpri__GetDigestSize(state->hashAlg); |
Vadim Sukhomlinov | 6a2d0e0 | 2019-08-01 18:18:56 -0700 | [diff] [blame] | 537 | |
Vadim Bendebury | 5679752 | 2015-05-20 10:32:25 -0700 | [diff] [blame] | 538 | _cpri__CompleteHash(hashState, digestSize, digest); |
| 539 | // Using the local hash state, do a hash with the oPad |
| 540 | if(_cpri__StartHash(state->hashAlg, FALSE, &localState) != digestSize) |
| 541 | return 0; |
| 542 | _cpri__UpdateHash(&localState, oPadKey->size, oPadKey->buffer); |
| 543 | _cpri__UpdateHash(&localState, digestSize, digest); |
| 544 | return _cpri__CompleteHash(&localState, dOutSize, dOut); |
| 545 | } |
| 546 | // |
| 547 | // |
| 548 | // Mask and Key Generation Functions |
| 549 | // |
| 550 | // _crypi_MGF1() |
| 551 | // |
| 552 | // This function performs MGF1 using the selected hash. MGF1 is T(n) = T(n-1) || H(seed || counter). This |
| 553 | // function returns the length of the mask produced which could be zero if the digest algorithm is not |
| 554 | // supported |
| 555 | // |
| 556 | // Return Value Meaning |
| 557 | // |
| 558 | // 0 hash algorithm not supported |
| 559 | // >0 should be the same as mSize |
| 560 | // |
| 561 | LIB_EXPORT CRYPT_RESULT |
| 562 | _cpri__MGF1( |
| 563 | UINT32 mSize, // IN: length of the mask to be produced |
| 564 | BYTE *mask, // OUT: buffer to receive the mask |
| 565 | TPM_ALG_ID hashAlg, // IN: hash to use |
| 566 | UINT32 sSize, // IN: size of the seed |
| 567 | BYTE *seed // IN: seed size |
| 568 | ) |
| 569 | { |
Vadim Sukhomlinov | 6a2d0e0 | 2019-08-01 18:18:56 -0700 | [diff] [blame] | 570 | EVP_MD_CTX *hashContext; |
Vadim Bendebury | 5679752 | 2015-05-20 10:32:25 -0700 | [diff] [blame] | 571 | EVP_MD *hashServer = NULL; |
| 572 | CRYPT_RESULT retVal = 0; |
| 573 | BYTE b[MAX_DIGEST_SIZE]; // temp buffer in case mask is not an |
| 574 | // even multiple of a full digest |
| 575 | CRYPT_RESULT dSize = _cpri__GetDigestSize(hashAlg); |
| 576 | unsigned int digestSize = (UINT32)dSize; |
| 577 | UINT32 remaining; |
| 578 | UINT32 counter; |
| 579 | BYTE swappedCounter[4]; |
| 580 | // Parameter check |
| 581 | if(mSize > (1024*16)) // Semi-arbitrary maximum |
| 582 | FAIL(FATAL_ERROR_INTERNAL); |
| 583 | // If there is no digest to compute return |
| 584 | if(dSize <= 0) |
| 585 | return 0; |
Vadim Bendebury | 5679752 | 2015-05-20 10:32:25 -0700 | [diff] [blame] | 586 | hashServer = GetHashServer(hashAlg); // Find the hash server |
| 587 | if(hashServer == NULL) |
| 588 | // If there is no server, then there is no digest |
| 589 | return 0; |
Vadim Sukhomlinov | 6a2d0e0 | 2019-08-01 18:18:56 -0700 | [diff] [blame] | 590 | if ((hashContext = EVP_MD_CTX_new()) == NULL) |
| 591 | FAIL(FATAL_ERROR_INTERNAL); |
Vadim Bendebury | 5679752 | 2015-05-20 10:32:25 -0700 | [diff] [blame] | 592 | for(counter = 0, remaining = mSize; remaining > 0; counter++) |
| 593 | { |
| 594 | // Because the system may be either Endian... |
| 595 | UINT32_TO_BYTE_ARRAY(counter, swappedCounter); |
| 596 | // Start the hash and include the seed and counter |
Vadim Sukhomlinov | 6a2d0e0 | 2019-08-01 18:18:56 -0700 | [diff] [blame] | 597 | if( (EVP_DigestInit_ex(hashContext, hashServer, NULL) != 1) |
| 598 | || (EVP_DigestUpdate(hashContext, seed, sSize) != 1) |
| 599 | || (EVP_DigestUpdate(hashContext, swappedCounter, 4) != 1) |
Vadim Bendebury | 5679752 | 2015-05-20 10:32:25 -0700 | [diff] [blame] | 600 | ) |
| 601 | FAIL(FATAL_ERROR_INTERNAL); |
| 602 | // Handling the completion depends on how much space remains in the mask |
| 603 | // buffer. If it can hold the entire digest, put it there. If not |
| 604 | // put the digest in a temp buffer and only copy the amount that |
| 605 | // will fit into the mask buffer. |
| 606 | if(remaining < (unsigned)dSize) |
| 607 | { |
Vadim Sukhomlinov | 6a2d0e0 | 2019-08-01 18:18:56 -0700 | [diff] [blame] | 608 | if(EVP_DigestFinal_ex(hashContext, b, &digestSize) != 1) |
Vadim Bendebury | 5679752 | 2015-05-20 10:32:25 -0700 | [diff] [blame] | 609 | FAIL(FATAL_ERROR_INTERNAL); |
| 610 | memcpy(mask, b, remaining); |
| 611 | break; |
| 612 | } |
| 613 | else |
| 614 | { |
Vadim Sukhomlinov | 6a2d0e0 | 2019-08-01 18:18:56 -0700 | [diff] [blame] | 615 | if(EVP_DigestFinal_ex(hashContext, mask, &digestSize) != 1) |
Vadim Bendebury | 5679752 | 2015-05-20 10:32:25 -0700 | [diff] [blame] | 616 | FAIL(FATAL_ERROR_INTERNAL); |
| 617 | remaining -= dSize; |
| 618 | mask = &mask[dSize]; |
| 619 | } |
| 620 | retVal = (CRYPT_RESULT)mSize; |
Vadim Sukhomlinov | 6a2d0e0 | 2019-08-01 18:18:56 -0700 | [diff] [blame] | 621 | } |
| 622 | EVP_MD_CTX_free(hashContext); |
Vadim Bendebury | 5679752 | 2015-05-20 10:32:25 -0700 | [diff] [blame] | 623 | return retVal; |
| 624 | } |
| 625 | // |
| 626 | // |
| 627 | // _cpri_KDFa() |
| 628 | // |
| 629 | // This function performs the key generation according to Part 1 of the TPM specification. |
| 630 | // This function returns the number of bytes generated which may be zero. |
| 631 | // The key and keyStream pointers are not allowed to be NULL. The other pointer values may be NULL. |
| 632 | // The value of sizeInBits must be no larger than (2^18)-1 = 256K bits (32385 bytes). |
| 633 | // The once parameter is set to allow incremental generation of a large value. If this flag is TRUE, |
| 634 | // sizeInBits will be used in the HMAC computation but only one iteration of the KDF is performed. This |
| 635 | // would be used for XOR obfuscation so that the mask value can be generated in digest-sized chunks |
| 636 | // rather than having to be generated all at once in an arbitrarily large buffer and then XORed() into the |
| 637 | // result. If once is TRUE, then sizeInBits must be a multiple of 8. |
| 638 | // Any error in the processing of this command is considered fatal. |
| 639 | // |
| 640 | // Return Value Meaning |
| 641 | // |
| 642 | // 0 hash algorithm is not supported or is TPM_ALG_NULL |
| 643 | // >0 the number of bytes in the keyStream buffer |
| 644 | // |
| 645 | LIB_EXPORT UINT16 |
| 646 | _cpri__KDFa( |
| 647 | TPM_ALG_ID hashAlg, // IN: hash algorithm used in HMAC |
| 648 | TPM2B *key, // IN: HMAC key |
| 649 | const char *label, // IN: a 0-byte terminated label used in KDF |
| 650 | TPM2B *contextU, // IN: context U |
| 651 | TPM2B *contextV, // IN: context V |
| 652 | UINT32 sizeInBits, // IN: size of generated key in bit |
| 653 | BYTE *keyStream, // OUT: key buffer |
| 654 | UINT32 *counterInOut, // IN/OUT: caller may provide the iteration |
| 655 | // counter for incremental operations to |
| 656 | // avoid large intermediate buffers. |
| 657 | BOOL once // IN: TRUE if only one iteration is performed |
| 658 | // FALSE if iteration count determined by |
| 659 | // "sizeInBits" |
| 660 | ) |
| 661 | { |
| 662 | UINT32 counter = 0; // counter value |
| 663 | INT32 lLen = 0; // length of the label |
| 664 | INT16 hLen; // length of the hash |
| 665 | INT16 bytes; // number of bytes to produce |
| 666 | BYTE *stream = keyStream; |
| 667 | BYTE marshaledUint32[4]; |
Vadim Sukhomlinov | 6a2d0e0 | 2019-08-01 18:18:56 -0700 | [diff] [blame] | 668 | CPRI_HASH_STATE hashState = {}; |
Vadim Bendebury | 5679752 | 2015-05-20 10:32:25 -0700 | [diff] [blame] | 669 | TPM2B_MAX_HASH_BLOCK hmacKey; |
| 670 | pAssert(key != NULL && keyStream != NULL); |
| 671 | pAssert(once == FALSE || (sizeInBits & 7) == 0); |
| 672 | if(counterInOut != NULL) |
| 673 | counter = *counterInOut; |
| 674 | // Prepare label buffer. Calculate its size and keep the last 0 byte |
| 675 | if(label != NULL) |
| 676 | for(lLen = 0; label[lLen++] != 0; ); |
| 677 | // Get the hash size. If it is less than or 0, either the |
| 678 | // algorithm is not supported or the hash is TPM_ALG_NULL |
| 679 | // |
| 680 | // In either case the digest size is zero. This is the only return |
| 681 | // other than the one at the end. All other exits from this function |
| 682 | // are fatal errors. After we check that the algorithm is supported |
| 683 | // anything else that goes wrong is an implementation flaw. |
| 684 | if((hLen = (INT16) _cpri__GetDigestSize(hashAlg)) == 0) |
| 685 | return 0; |
| 686 | // If the size of the request is larger than the numbers will handle, |
| 687 | // it is a fatal error. |
| 688 | pAssert(((sizeInBits + 7)/ 8) <= INT16_MAX); |
| 689 | bytes = once ? hLen : (INT16)((sizeInBits + 7) / 8); |
| 690 | // Generate required bytes |
| 691 | for (; bytes > 0; stream = &stream[hLen], bytes = bytes - hLen) |
| 692 | { |
| 693 | if(bytes < hLen) |
| 694 | hLen = bytes; |
| 695 | counter++; |
| 696 | // Start HMAC |
| 697 | if(_cpri__StartHMAC(hashAlg, |
| 698 | FALSE, |
| 699 | &hashState, |
| 700 | key->size, |
| 701 | &key->buffer[0], |
| 702 | &hmacKey.b) <= 0) |
| 703 | FAIL(FATAL_ERROR_INTERNAL); |
| 704 | // Adding counter |
| 705 | UINT32_TO_BYTE_ARRAY(counter, marshaledUint32); |
| 706 | _cpri__UpdateHash(&hashState, sizeof(UINT32), marshaledUint32); |
| 707 | // Adding label |
| 708 | if(label != NULL) |
| 709 | _cpri__UpdateHash(&hashState, lLen, (BYTE *)label); |
| 710 | // Adding contextU |
| 711 | if(contextU != NULL) |
| 712 | _cpri__UpdateHash(&hashState, contextU->size, contextU->buffer); |
| 713 | // Adding contextV |
| 714 | if(contextV != NULL) |
| 715 | _cpri__UpdateHash(&hashState, contextV->size, contextV->buffer); |
| 716 | // Adding size in bits |
| 717 | UINT32_TO_BYTE_ARRAY(sizeInBits, marshaledUint32); |
| 718 | _cpri__UpdateHash(&hashState, sizeof(UINT32), marshaledUint32); |
| 719 | // Compute HMAC. At the start of each iteration, hLen is set |
| 720 | // to the smaller of hLen and bytes. This causes bytes to decrement |
| 721 | // exactly to zero to complete the loop |
| 722 | _cpri__CompleteHMAC(&hashState, &hmacKey.b, hLen, stream); |
| 723 | } |
| 724 | // Mask off bits if the required bits is not a multiple of byte size |
| 725 | if((sizeInBits % 8) != 0) |
| 726 | keyStream[0] &= ((1 << (sizeInBits % 8)) - 1); |
| 727 | if(counterInOut != NULL) |
| 728 | *counterInOut = counter; |
| 729 | return (CRYPT_RESULT)((sizeInBits + 7)/8); |
| 730 | } |
| 731 | // |
| 732 | // |
| 733 | // |
| 734 | // _cpri__KDFe() |
| 735 | // |
| 736 | // KDFe() as defined in TPM specification part 1. |
| 737 | // This function returns the number of bytes generated which may be zero. |
| 738 | // The Z and keyStream pointers are not allowed to be NULL. The other pointer values may be NULL. The |
| 739 | // value of sizeInBits must be no larger than (2^18)-1 = 256K bits (32385 bytes). Any error in the processing |
| 740 | // of this command is considered fatal. |
| 741 | // |
| 742 | // Return Value Meaning |
| 743 | // |
| 744 | // 0 hash algorithm is not supported or is TPM_ALG_NULL |
| 745 | // >0 the number of bytes in the keyStream buffer |
| 746 | // |
| 747 | LIB_EXPORT UINT16 |
| 748 | _cpri__KDFe( |
| 749 | TPM_ALG_ID hashAlg, // IN: hash algorithm used in HMAC |
| 750 | TPM2B *Z, // IN: Z |
| 751 | const char *label, // IN: a 0 terminated label using in KDF |
| 752 | TPM2B *partyUInfo, // IN: PartyUInfo |
| 753 | TPM2B *partyVInfo, // IN: PartyVInfo |
| 754 | UINT32 sizeInBits, // IN: size of generated key in bit |
| 755 | BYTE *keyStream // OUT: key buffer |
| 756 | ) |
| 757 | { |
| 758 | UINT32 counter = 0; // counter value |
| 759 | UINT32 lSize = 0; |
| 760 | BYTE *stream = keyStream; |
Vadim Sukhomlinov | 6a2d0e0 | 2019-08-01 18:18:56 -0700 | [diff] [blame] | 761 | CPRI_HASH_STATE hashState = {}; |
Vadim Bendebury | 5679752 | 2015-05-20 10:32:25 -0700 | [diff] [blame] | 762 | INT16 hLen = (INT16) _cpri__GetDigestSize(hashAlg); |
| 763 | INT16 bytes; // number of bytes to generate |
| 764 | BYTE marshaledUint32[4]; |
| 765 | pAssert( keyStream != NULL |
| 766 | && Z != NULL |
| 767 | && ((sizeInBits + 7) / 8) < INT16_MAX); |
| 768 | if(hLen == 0) |
| 769 | return 0; |
| 770 | bytes = (INT16)((sizeInBits + 7) / 8); |
| 771 | // Prepare label buffer. Calculate its size and keep the last 0 byte |
| 772 | if(label != NULL) |
| 773 | for(lSize = 0; label[lSize++] != 0;); |
| 774 | // Generate required bytes |
| 775 | //The inner loop of that KDF uses: |
| 776 | // Hashi := H(counter | Z | OtherInfo) (5) |
| 777 | // Where: |
| 778 | // Hashi the hash generated on the i-th iteration of the loop. |
| 779 | // H() an approved hash function |
| 780 | // counter a 32-bit counter that is initialized to 1 and incremented |
| 781 | // on each iteration |
| 782 | // Z the X coordinate of the product of a public ECC key and a |
| 783 | // different private ECC key. |
| 784 | // OtherInfo a collection of qualifying data for the KDF defined below. |
| 785 | // In this specification, OtherInfo will be constructed by: |
| 786 | // OtherInfo := Use | PartyUInfo | PartyVInfo |
| 787 | for (; bytes > 0; stream = &stream[hLen], bytes = bytes - hLen) |
| 788 | { |
| 789 | if(bytes < hLen) |
| 790 | hLen = bytes; |
| 791 | // |
| 792 | counter++; |
| 793 | // Start hash |
| 794 | if(_cpri__StartHash(hashAlg, FALSE, &hashState) == 0) |
| 795 | return 0; |
| 796 | // Add counter |
| 797 | UINT32_TO_BYTE_ARRAY(counter, marshaledUint32); |
| 798 | _cpri__UpdateHash(&hashState, sizeof(UINT32), marshaledUint32); |
| 799 | // Add Z |
| 800 | if(Z != NULL) |
| 801 | _cpri__UpdateHash(&hashState, Z->size, Z->buffer); |
| 802 | // Add label |
| 803 | if(label != NULL) |
| 804 | _cpri__UpdateHash(&hashState, lSize, (BYTE *)label); |
| 805 | else |
| 806 | // The SP800-108 specification requires a zero between the label |
| 807 | // and the context. |
| 808 | _cpri__UpdateHash(&hashState, 1, (BYTE *)""); |
| 809 | // Add PartyUInfo |
| 810 | if(partyUInfo != NULL) |
| 811 | _cpri__UpdateHash(&hashState, partyUInfo->size, partyUInfo->buffer); |
| 812 | // Add PartyVInfo |
| 813 | if(partyVInfo != NULL) |
| 814 | _cpri__UpdateHash(&hashState, partyVInfo->size, partyVInfo->buffer); |
| 815 | // Compute Hash. hLen was changed to be the smaller of bytes or hLen |
| 816 | // at the start of each iteration. |
| 817 | _cpri__CompleteHash(&hashState, hLen, stream); |
| 818 | } |
| 819 | // Mask off bits if the required bits is not a multiple of byte size |
| 820 | if((sizeInBits % 8) != 0) |
| 821 | keyStream[0] &= ((1 << (sizeInBits % 8)) - 1); |
| 822 | return (CRYPT_RESULT)((sizeInBits + 7) / 8); |
| 823 | } |