/* 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 #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