• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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