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 //** Description
36 // This file contains the entry point for the simulator.
37 
38 //** Includes, Defines, Data Definitions, and Function Prototypes
39 #include "TpmBuildSwitches.h"
40 
41 #include <stdlib.h>
42 #include <stdio.h>
43 #include <stdint.h>
44 #include <stdbool.h>
45 #include <ctype.h>
46 #include <string.h>
47 
48 #ifdef _MSC_VER
49 #   pragma warning(push, 3)
50 #   include <windows.h>
51 #   include <winsock.h>
52 #   pragma warning(pop)
53 #elif defined(__unix__)
54 #   define _strcmpi strcasecmp
55     typedef int SOCKET;
56 #else
57 #   error "Unsupported platform."
58 #endif
59 
60 
61 #include "TpmTcpProtocol.h"
62 #include "Manufacture_fp.h"
63 #include "Platform_fp.h"
64 #include "Simulator_fp.h"
65 
66 #define PURPOSE \
67 "TPM 2.0 Reference Simulator.\n"  \
68 "Copyright (c) Microsoft Corporation. All rights reserved."
69 
70 #define DEFAULT_TPM_PORT 2321
71 
72 // Information about command line arguments (does not include program name)
73 static uint32_t     s_ArgsMask = 0;     // Bit mask of unmatched command line args
74 static int          s_Argc = 0;
75 static const char **s_Argv = NULL;
76 
77 
78 //** Functions
79 
80 #if DEBUG
81 //*** Assert()
82 // This function implements a run-time assertion.
83 // Computation of its parameters must not result in any side effects, as these
84 // computations will be stripped from the release builds.
Assert(bool cond,const char * msg)85 static void Assert (bool cond, const char* msg)
86 {
87     if (cond)
88         return;
89     fputs(msg, stderr);
90     exit(2);
91 }
92 #else
93 #define Assert(cond, msg)
94 #endif
95 
96 //*** Usage()
97 // This function prints the proper calling sequence for the simulator.
98 static void
Usage(const char * programName)99 Usage(
100     const char          *programName
101 )
102 {
103     fprintf(stderr, "%s\n\n", PURPOSE);
104     fprintf(stderr, "Usage:  %s [PortNum] [opts]\n\n"
105         "Starts the TPM server listening on TCP port PortNum (by default %d).\n\n"
106         "An option can be in the short form (one letter preceded with '-' or '/')\n"
107         "or in the full form (preceded with '--' or no option marker at all).\n"
108         "Possible options are:\n"
109         "   -h (--help) or ? - print this message\n"
110         "   -m (--manufacture) - forces NV state of the TPM simulator to be "
111         "(re)manufactured\n",
112         programName, DEFAULT_TPM_PORT);
113     exit(1);
114 }
115 
116 //*** CmdLineParser_Init()
117 // This function initializes command line option parser.
118 static bool
CmdLineParser_Init(int argc,char * argv[],int maxOpts)119 CmdLineParser_Init(
120     int argc,
121     char *argv[],
122     int maxOpts
123     )
124 {
125     if (argc == 1)
126         return false;
127 
128     if (maxOpts && (argc - 1) > maxOpts)
129     {
130         fprintf(stderr, "No more than %d options can be specified\n\n", maxOpts);
131         Usage(argv[0]);
132     }
133 
134     s_Argc = argc - 1;
135     s_Argv = (const char**)(argv + 1);
136     s_ArgsMask = (1 << s_Argc) - 1;
137     return true;
138 }
139 
140 //*** CmdLineParser_More()
141 // Returns true if there are unparsed options still.
142 static bool
CmdLineParser_More(void)143 CmdLineParser_More(
144     void
145 )
146 {
147     return s_ArgsMask != 0;
148 }
149 
150 //*** CmdLineParser_IsOpt()
151 // This function determines if the given command line parameter represents a valid
152 // option.
153 static bool
CmdLineParser_IsOpt(const char * opt,const char * optFull,const char * optShort,bool dashed)154 CmdLineParser_IsOpt(
155     const char* opt,        // Command line parameter to check
156     const char* optFull,    // Expected full name
157     const char* optShort,   // Expected short (single letter) name
158     bool dashed             // The parameter is preceded by a single dash
159     )
160 {
161     return 0 == strcmp(opt, optFull)
162         || (optShort && opt[0] == optShort[0] && opt[1] == 0)
163         || (dashed && opt[0] == '-' && 0 == strcmp(opt + 1, optFull));
164 }
165 
166 //*** CmdLineParser_IsOptPresent()
167 // This function determines if the given command line parameter represents a valid
168 // option.
169 static bool
CmdLineParser_IsOptPresent(const char * optFull,const char * optShort)170 CmdLineParser_IsOptPresent(
171     const char* optFull,
172     const char* optShort
173     )
174 {
175     int         i;
176     int         curArgBit;
177     Assert(s_Argv != NULL,
178         "InitCmdLineOptParser(argc, argv) has not been invoked\n");
179     Assert(optFull && optFull[0],
180         "Full form of a command line option must be present.\n"
181         "If only a short (single letter) form is supported, it must be"
182         "specified as the full one.\n");
183     Assert(!optShort || (optShort[0] && !optShort[1]),
184         "If a short form of an option is specified, it must consist "
185         "of a single letter only.\n");
186 
187     if (!CmdLineParser_More())
188         return false;
189 
190     for (i = 0, curArgBit = 1; i < s_Argc; ++i, curArgBit <<= 1)
191     {
192         const char* opt = s_Argv[i];
193         if (   (s_ArgsMask & curArgBit) && opt
194             && (   0 == strcmp(opt, optFull)
195                 || (   (opt[0] == '/' || opt[0] == '-')
196                     && CmdLineParser_IsOpt(opt + 1, optFull, optShort,
197                                            opt[0] == '-'))))
198         {
199             s_ArgsMask ^= curArgBit;
200             return true;
201         }
202     }
203     return false;
204 }
205 
206 //*** CmdLineParser_Done()
207 // This function notifies the parser that no more options are needed.
208 static void
CmdLineParser_Done(const char * programName)209 CmdLineParser_Done(
210     const char          *programName
211 )
212 {
213     char delim = ':';
214     int         i;
215     int         curArgBit;
216 
217     if (!CmdLineParser_More())
218         return;
219 
220     fprintf(stderr, "Command line contains unknown option%s",
221             s_ArgsMask & (s_ArgsMask - 1) ? "s" : "");
222     for (i = 0, curArgBit = 1; i < s_Argc; ++i, curArgBit <<= 1)
223     {
224         if (s_ArgsMask & curArgBit)
225         {
226             fprintf(stderr, "%c %s", delim, s_Argv[i]);
227             delim = ',';
228         }
229     }
230     fprintf(stderr, "\n\n");
231     Usage(programName);
232 }
233 
234 //*** main()
235 // This is the main entry point for the simulator.
236 // It registers the interface and starts listening for clients
237 int
main(int argc,char * argv[])238 main(
239     int              argc,
240     char            *argv[]
241     )
242 {
243     bool    manufacture = false;
244     int     PortNum = DEFAULT_TPM_PORT;
245 
246     // Parse command line options
247 
248     if (CmdLineParser_Init(argc, argv, 2))
249     {
250         if (   CmdLineParser_IsOptPresent("?", "?")
251             || CmdLineParser_IsOptPresent("help", "h"))
252         {
253             Usage(argv[0]);
254         }
255         if (CmdLineParser_IsOptPresent("manufacture", "m"))
256         {
257             manufacture = true;
258         }
259         if (CmdLineParser_More())
260         {
261             int     i;
262             for (i = 0; i < s_Argc; ++i)
263             {
264                 char *nptr = NULL;
265                 int portNum = (int)strtol(s_Argv[i], &nptr, 0);
266                 if (s_Argv[i] != nptr)
267                 {
268                     // A numeric option is found
269                     if(!*nptr && portNum > 0 && portNum < 65535)
270                     {
271                         PortNum = portNum;
272                         s_ArgsMask ^= 1 << i;
273                         break;
274                     }
275                     fprintf(stderr, "Invalid numeric option %s\n\n", s_Argv[i]);
276                     Usage(argv[0]);
277                 }
278             }
279         }
280         CmdLineParser_Done(argv[0]);
281     }
282     printf("LIBRARY_COMPATIBILITY_CHECK is %s\n",
283         (LIBRARY_COMPATIBILITY_CHECK ? "ON" : "OFF"));
284     // Enable NV memory
285     _plat__NVEnable(NULL);
286 
287     if (manufacture || _plat__NVNeedsManufacture())
288     {
289         printf("Manufacturing NV state...\n");
290         if(TPM_Manufacture(1) != 0)
291         {
292             // if the manufacture didn't work, then make sure that the NV file doesn't
293             // survive. This prevents manufacturing failures from being ignored the
294             // next time the code is run.
295             _plat__NVDisable(1);
296             exit(1);
297         }
298         // Coverage test - repeated manufacturing attempt
299         if(TPM_Manufacture(0) != 1)
300         {
301             exit(2);
302         }
303         // Coverage test - re-manufacturing
304         TPM_TearDown();
305         if(TPM_Manufacture(1) != 0)
306         {
307             exit(3);
308         }
309     }
310     // Disable NV memory
311     _plat__NVDisable(0);
312 
313     StartTcpServer(PortNum);
314     return EXIT_SUCCESS;
315 }
316 
317