/* Microsoft Reference Implementation for TPM 2.0 | |
* | |
* The copyright in this software is being made available under the BSD License, | |
* included below. This software may be subject to other third party and | |
* contributor rights, including patent rights, and no such rights are granted | |
* under this license. | |
* | |
* Copyright (c) Microsoft Corporation | |
* | |
* All rights reserved. | |
* | |
* BSD License | |
* | |
* Redistribution and use in source and binary forms, with or without modification, | |
* are permitted provided that the following conditions are met: | |
* | |
* Redistributions of source code must retain the above copyright notice, this list | |
* of conditions and the following disclaimer. | |
* | |
* Redistributions in binary form must reproduce the above copyright notice, this | |
* list of conditions and the following disclaimer in the documentation and/or | |
* other materials provided with the distribution. | |
* | |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ""AS IS"" | |
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR | |
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | |
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
*/ | |
//** Introduction | |
// This file contains the functions to implement the RSA key cache that can be used | |
// to speed up simulation. | |
// | |
// Only one key is created for each supported key size and it is returned whenever | |
// a key of that size is requested. | |
// | |
// If desired, the key cache can be populated from a file. This allows multiple | |
// TPM to run with the same RSA keys. Also, when doing simulation, the DRBG will | |
// use preset sequences so it is not too hard to repeat sequences for debug or | |
// profile or stress. | |
// | |
// When the key cache is enabled, a call to CryptRsaGenerateKey() will call the | |
// GetCachedRsaKey(). If the cache is enabled and populated, then the cached key | |
// of the requested size is returned. If a key of the requested size is not | |
// available, the no key is loaded and the requested key will need to be generated. | |
// If the cache is not populated, the TPM will open a file that has the appropriate | |
// name for the type of keys required (CRT or no-CRT). If the file is the right | |
// size, it is used. If the file doesn't exist or the file does not have the correct | |
// size, the TMP will populate the cache with new keys of the required size and | |
// write the cache data to the file so that they will be available the next time. | |
// | |
// Currently, if two simulations are being run with TPM's that have different RSA | |
// key sizes (e.g,, one with 1024 and 2048 and another with 2048 and 3072, then the | |
// files will not match for the both of them and they will both try to overwrite | |
// the other's cache file. I may try to do something about this if necessary. | |
//** Includes, Types, Locals, and Defines | |
#include "Tpm.h" | |
#if USE_RSA_KEY_CACHE | |
#include <stdio.h> | |
#include "RsaKeyCache_fp.h" | |
#if CRT_FORMAT_RSA == YES | |
#define CACHE_FILE_NAME "RsaKeyCacheCrt.data" | |
#else | |
#define CACHE_FILE_NAME "RsaKeyCacheNoCrt.data" | |
#endif | |
typedef struct _RSA_KEY_CACHE_ | |
{ | |
TPM2B_PUBLIC_KEY_RSA publicModulus; | |
TPM2B_PRIVATE_KEY_RSA privateExponent; | |
} RSA_KEY_CACHE; | |
// Determine the number of RSA key sizes for the cache | |
TPMI_RSA_KEY_BITS SupportedRsaKeySizes[] = { | |
#if RSA_1024 | |
1024, | |
#endif | |
#if RSA_2048 | |
2048, | |
#endif | |
#if RSA_3072 | |
3072, | |
#endif | |
#if RSA_4096 | |
4096, | |
#endif | |
0 | |
}; | |
#define RSA_KEY_CACHE_ENTRIES (RSA_1024 + RSA_2048 + RSA_3072 + RSA_4096) | |
// The key cache holds one entry for each of the supported key sizes | |
RSA_KEY_CACHE s_rsaKeyCache[RSA_KEY_CACHE_ENTRIES]; | |
// Indicates if the key cache is loaded. It can be loaded and enabled or disabled. | |
BOOL s_keyCacheLoaded = 0; | |
// Indicates if the key cache is enabled | |
int s_rsaKeyCacheEnabled = FALSE; | |
//*** RsaKeyCacheControl() | |
// Used to enable and disable the RSA key cache. | |
LIB_EXPORT void | |
RsaKeyCacheControl( | |
int state | |
) | |
{ | |
s_rsaKeyCacheEnabled = state; | |
} | |
//*** InitializeKeyCache() | |
// This will initialize the key cache and attempt to write it to a file for later | |
// use. | |
// Return Type: BOOL | |
// TRUE(1) success | |
// FALSE(0) failure | |
static BOOL | |
InitializeKeyCache( | |
TPMT_PUBLIC *publicArea, | |
TPMT_SENSITIVE *sensitive, | |
RAND_STATE *rand // IN: if not NULL, the deterministic | |
// RNG state | |
) | |
{ | |
int index; | |
TPM_KEY_BITS keySave = publicArea->parameters.rsaDetail.keyBits; | |
BOOL OK = TRUE; | |
// | |
s_rsaKeyCacheEnabled = FALSE; | |
for(index = 0; OK && index < RSA_KEY_CACHE_ENTRIES; index++) | |
{ | |
publicArea->parameters.rsaDetail.keyBits | |
= SupportedRsaKeySizes[index]; | |
OK = (CryptRsaGenerateKey(publicArea, sensitive, rand) == TPM_RC_SUCCESS); | |
if(OK) | |
{ | |
s_rsaKeyCache[index].publicModulus = publicArea->unique.rsa; | |
s_rsaKeyCache[index].privateExponent = sensitive->sensitive.rsa; | |
} | |
} | |
publicArea->parameters.rsaDetail.keyBits = keySave; | |
s_keyCacheLoaded = OK; | |
#if SIMULATION && USE_RSA_KEY_CACHE && USE_KEY_CACHE_FILE | |
if(OK) | |
{ | |
FILE *cacheFile; | |
const char *fn = CACHE_FILE_NAME; | |
#if defined _MSC_VER | |
if(fopen_s(&cacheFile, fn, "w+b") != 0) | |
#else | |
cacheFile = fopen(fn, "w+b"); | |
if(NULL == cacheFile) | |
#endif | |
{ | |
printf("Can't open %s for write.\n", fn); | |
} | |
else | |
{ | |
fseek(cacheFile, 0, SEEK_SET); | |
if(fwrite(s_rsaKeyCache, 1, sizeof(s_rsaKeyCache), cacheFile) | |
!= sizeof(s_rsaKeyCache)) | |
{ | |
printf("Error writing cache to %s.", fn); | |
} | |
} | |
if(cacheFile) | |
fclose(cacheFile); | |
} | |
#endif | |
return s_keyCacheLoaded; | |
} | |
//*** KeyCacheLoaded() | |
// Checks that key cache is loaded. | |
// Return Type: BOOL | |
// TRUE(1) cache loaded | |
// FALSE(0) cache not loaded | |
static BOOL | |
KeyCacheLoaded( | |
TPMT_PUBLIC *publicArea, | |
TPMT_SENSITIVE *sensitive, | |
RAND_STATE *rand // IN: if not NULL, the deterministic | |
// RNG state | |
) | |
{ | |
#if SIMULATION && USE_RSA_KEY_CACHE && USE_KEY_CACHE_FILE | |
if(!s_keyCacheLoaded) | |
{ | |
FILE *cacheFile; | |
const char * fn = CACHE_FILE_NAME; | |
#if defined _MSC_VER && 1 | |
if(fopen_s(&cacheFile, fn, "r+b") == 0) | |
#else | |
cacheFile = fopen(fn, "r+b"); | |
if(NULL != cacheFile) | |
#endif | |
{ | |
fseek(cacheFile, 0L, SEEK_END); | |
if(ftell(cacheFile) == sizeof(s_rsaKeyCache)) | |
{ | |
fseek(cacheFile, 0L, SEEK_SET); | |
s_keyCacheLoaded = ( | |
fread(&s_rsaKeyCache, 1, sizeof(s_rsaKeyCache), cacheFile) | |
== sizeof(s_rsaKeyCache)); | |
} | |
fclose(cacheFile); | |
} | |
} | |
#endif | |
if(!s_keyCacheLoaded) | |
s_rsaKeyCacheEnabled = InitializeKeyCache(publicArea, sensitive, rand); | |
return s_keyCacheLoaded; | |
} | |
//*** GetCachedRsaKey() | |
// Return Type: BOOL | |
// TRUE(1) key loaded | |
// FALSE(0) key not loaded | |
BOOL | |
GetCachedRsaKey( | |
TPMT_PUBLIC *publicArea, | |
TPMT_SENSITIVE *sensitive, | |
RAND_STATE *rand // IN: if not NULL, the deterministic | |
// RNG state | |
) | |
{ | |
int keyBits = publicArea->parameters.rsaDetail.keyBits; | |
int index; | |
// | |
if(KeyCacheLoaded(publicArea, sensitive, rand)) | |
{ | |
for(index = 0; index < RSA_KEY_CACHE_ENTRIES; index++) | |
{ | |
if((s_rsaKeyCache[index].publicModulus.t.size * 8) == keyBits) | |
{ | |
publicArea->unique.rsa = s_rsaKeyCache[index].publicModulus; | |
sensitive->sensitive.rsa = s_rsaKeyCache[index].privateExponent; | |
return TRUE; | |
} | |
} | |
return FALSE; | |
} | |
return s_keyCacheLoaded; | |
} | |
#endif // defined SIMULATION && defined USE_RSA_KEY_CACHE |