1 /* Microsoft Reference Implementation for TPM 2.0
2 *
3 * The copyright in this software is being made available under the BSD License,
4 * included below. This software may be subject to other third party and
5 * contributor rights, including patent rights, and no such rights are granted
6 * under this license.
7 *
8 * Copyright (c) Microsoft Corporation
9 *
10 * All rights reserved.
11 *
12 * BSD License
13 *
14 * Redistribution and use in source and binary forms, with or without modification,
15 * are permitted provided that the following conditions are met:
16 *
17 * Redistributions of source code must retain the above copyright notice, this list
18 * of conditions and the following disclaimer.
19 *
20 * Redistributions in binary form must reproduce the above copyright notice, this
21 * list of conditions and the following disclaimer in the documentation and/or
22 * other materials provided with the distribution.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ""AS IS""
25 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
28 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
31 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35 //** Introduction
36 // This file contains the functions to implement the RSA key cache that can be used
37 // to speed up simulation.
38 //
39 // Only one key is created for each supported key size and it is returned whenever
40 // a key of that size is requested.
41 //
42 // If desired, the key cache can be populated from a file. This allows multiple
43 // TPM to run with the same RSA keys. Also, when doing simulation, the DRBG will
44 // use preset sequences so it is not too hard to repeat sequences for debug or
45 // profile or stress.
46 //
47 // When the key cache is enabled, a call to CryptRsaGenerateKey() will call the
48 // GetCachedRsaKey(). If the cache is enabled and populated, then the cached key
49 // of the requested size is returned. If a key of the requested size is not
50 // available, the no key is loaded and the requested key will need to be generated.
51 // If the cache is not populated, the TPM will open a file that has the appropriate
52 // name for the type of keys required (CRT or no-CRT). If the file is the right
53 // size, it is used. If the file doesn't exist or the file does not have the correct
54 // size, the TMP will populate the cache with new keys of the required size and
55 // write the cache data to the file so that they will be available the next time.
56 //
57 // Currently, if two simulations are being run with TPM's that have different RSA
58 // key sizes (e.g,, one with 1024 and 2048 and another with 2048 and 3072, then the
59 // files will not match for the both of them and they will both try to overwrite
60 // the other's cache file. I may try to do something about this if necessary.
61
62 //** Includes, Types, Locals, and Defines
63
64 #include "Tpm.h"
65
66 #if USE_RSA_KEY_CACHE
67
68 #include <stdio.h>
69 #include "RsaKeyCache_fp.h"
70
71 #if CRT_FORMAT_RSA == YES
72 #define CACHE_FILE_NAME "RsaKeyCacheCrt.data"
73 #else
74 #define CACHE_FILE_NAME "RsaKeyCacheNoCrt.data"
75 #endif
76
77 typedef struct _RSA_KEY_CACHE_
78 {
79 TPM2B_PUBLIC_KEY_RSA publicModulus;
80 TPM2B_PRIVATE_KEY_RSA privateExponent;
81 } RSA_KEY_CACHE;
82
83 // Determine the number of RSA key sizes for the cache
84 TPMI_RSA_KEY_BITS SupportedRsaKeySizes[] = {
85 #if RSA_1024
86 1024,
87 #endif
88 #if RSA_2048
89 2048,
90 #endif
91 #if RSA_3072
92 3072,
93 #endif
94 #if RSA_4096
95 4096,
96 #endif
97 0
98 };
99
100 #define RSA_KEY_CACHE_ENTRIES (RSA_1024 + RSA_2048 + RSA_3072 + RSA_4096)
101
102 // The key cache holds one entry for each of the supported key sizes
103 RSA_KEY_CACHE s_rsaKeyCache[RSA_KEY_CACHE_ENTRIES];
104 // Indicates if the key cache is loaded. It can be loaded and enabled or disabled.
105 BOOL s_keyCacheLoaded = 0;
106
107 // Indicates if the key cache is enabled
108 int s_rsaKeyCacheEnabled = FALSE;
109
110 //*** RsaKeyCacheControl()
111 // Used to enable and disable the RSA key cache.
112 LIB_EXPORT void
RsaKeyCacheControl(int state)113 RsaKeyCacheControl(
114 int state
115 )
116 {
117 s_rsaKeyCacheEnabled = state;
118 }
119
120 //*** InitializeKeyCache()
121 // This will initialize the key cache and attempt to write it to a file for later
122 // use.
123 // Return Type: BOOL
124 // TRUE(1) success
125 // FALSE(0) failure
126 static BOOL
InitializeKeyCache(TPMT_PUBLIC * publicArea,TPMT_SENSITIVE * sensitive,RAND_STATE * rand)127 InitializeKeyCache(
128 TPMT_PUBLIC *publicArea,
129 TPMT_SENSITIVE *sensitive,
130 RAND_STATE *rand // IN: if not NULL, the deterministic
131 // RNG state
132 )
133 {
134 int index;
135 TPM_KEY_BITS keySave = publicArea->parameters.rsaDetail.keyBits;
136 BOOL OK = TRUE;
137 //
138 s_rsaKeyCacheEnabled = FALSE;
139 for(index = 0; OK && index < RSA_KEY_CACHE_ENTRIES; index++)
140 {
141 publicArea->parameters.rsaDetail.keyBits
142 = SupportedRsaKeySizes[index];
143 OK = (CryptRsaGenerateKey(publicArea, sensitive, rand) == TPM_RC_SUCCESS);
144 if(OK)
145 {
146 s_rsaKeyCache[index].publicModulus = publicArea->unique.rsa;
147 s_rsaKeyCache[index].privateExponent = sensitive->sensitive.rsa;
148 }
149 }
150 publicArea->parameters.rsaDetail.keyBits = keySave;
151 s_keyCacheLoaded = OK;
152 #if SIMULATION && USE_RSA_KEY_CACHE && USE_KEY_CACHE_FILE
153 if(OK)
154 {
155 FILE *cacheFile;
156 const char *fn = CACHE_FILE_NAME;
157
158 #if defined _MSC_VER
159 if(fopen_s(&cacheFile, fn, "w+b") != 0)
160 #else
161 cacheFile = fopen(fn, "w+b");
162 if(NULL == cacheFile)
163 #endif
164 {
165 printf("Can't open %s for write.\n", fn);
166 }
167 else
168 {
169 fseek(cacheFile, 0, SEEK_SET);
170 if(fwrite(s_rsaKeyCache, 1, sizeof(s_rsaKeyCache), cacheFile)
171 != sizeof(s_rsaKeyCache))
172 {
173 printf("Error writing cache to %s.", fn);
174 }
175 }
176 if(cacheFile)
177 fclose(cacheFile);
178 }
179 #endif
180 return s_keyCacheLoaded;
181 }
182
183 //*** KeyCacheLoaded()
184 // Checks that key cache is loaded.
185 // Return Type: BOOL
186 // TRUE(1) cache loaded
187 // FALSE(0) cache not loaded
188 static BOOL
KeyCacheLoaded(TPMT_PUBLIC * publicArea,TPMT_SENSITIVE * sensitive,RAND_STATE * rand)189 KeyCacheLoaded(
190 TPMT_PUBLIC *publicArea,
191 TPMT_SENSITIVE *sensitive,
192 RAND_STATE *rand // IN: if not NULL, the deterministic
193 // RNG state
194 )
195 {
196 #if SIMULATION && USE_RSA_KEY_CACHE && USE_KEY_CACHE_FILE
197 if(!s_keyCacheLoaded)
198 {
199 FILE *cacheFile;
200 const char * fn = CACHE_FILE_NAME;
201 #if defined _MSC_VER && 1
202 if(fopen_s(&cacheFile, fn, "r+b") == 0)
203 #else
204 cacheFile = fopen(fn, "r+b");
205 if(NULL != cacheFile)
206 #endif
207 {
208 fseek(cacheFile, 0L, SEEK_END);
209 if(ftell(cacheFile) == sizeof(s_rsaKeyCache))
210 {
211 fseek(cacheFile, 0L, SEEK_SET);
212 s_keyCacheLoaded = (
213 fread(&s_rsaKeyCache, 1, sizeof(s_rsaKeyCache), cacheFile)
214 == sizeof(s_rsaKeyCache));
215 }
216 fclose(cacheFile);
217 }
218 }
219 #endif
220 if(!s_keyCacheLoaded)
221 s_rsaKeyCacheEnabled = InitializeKeyCache(publicArea, sensitive, rand);
222 return s_keyCacheLoaded;
223 }
224
225 //*** GetCachedRsaKey()
226 // Return Type: BOOL
227 // TRUE(1) key loaded
228 // FALSE(0) key not loaded
229 BOOL
GetCachedRsaKey(TPMT_PUBLIC * publicArea,TPMT_SENSITIVE * sensitive,RAND_STATE * rand)230 GetCachedRsaKey(
231 TPMT_PUBLIC *publicArea,
232 TPMT_SENSITIVE *sensitive,
233 RAND_STATE *rand // IN: if not NULL, the deterministic
234 // RNG state
235 )
236 {
237 int keyBits = publicArea->parameters.rsaDetail.keyBits;
238 int index;
239 //
240 if(KeyCacheLoaded(publicArea, sensitive, rand))
241 {
242 for(index = 0; index < RSA_KEY_CACHE_ENTRIES; index++)
243 {
244 if((s_rsaKeyCache[index].publicModulus.t.size * 8) == keyBits)
245 {
246 publicArea->unique.rsa = s_rsaKeyCache[index].publicModulus;
247 sensitive->sensitive.rsa = s_rsaKeyCache[index].privateExponent;
248 return TRUE;
249 }
250 }
251 return FALSE;
252 }
253 return s_keyCacheLoaded;
254 }
255 #endif // defined SIMULATION && defined USE_RSA_KEY_CACHE
256