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
36 #if !defined(_MSC_VER) && defined(USE_PLATFORM_EPS)
37 #include <stdlib.h>
38 #include <memory.h>
39 #include <time.h>
40 #include <unistd.h>
41 #include <net/if.h>
42 #include <sys/ioctl.h>
43 #include <netinet/in.h>
44 #include <stdio.h>
45 #include <libudev.h>
46 #include <sys/stat.h>
47
48 #include "Tpm.h"
49 #include "Platform_fp.h"
50
51 #define DEVICEID_SIZE 48
52
53 // This extension is needed as TPM2B_STRING only define TPM2B variable when #GLOBAL_C is defined.
54 #define TPM2B_STRING_EXTENSION(name, value) \
55 TPM2B_STRING(name, value); \
56 const TPM2B_##name##_ name##_ = STRING_INITIALIZER(value); \
57 const TPM2B *name = &name##_.b
58
59 TPM2B_STRING_EXTENSION(EPS_CREATION, "EPS Creation");
60
61 // Definition for Device ID value.
62 TPM2B_TYPE(DEVICEID, DEVICEID_SIZE);
63 const unsigned int MAC_ADDRESS_MAXIMUM_SIZE = 6;
64
65 // This value is used to store device id derived from hardware parameters.
66 static TPM2B_DEVICEID deviceID = {0};
67 static BOOL isDeviceIDSet = FALSE;
68
69 // Read mac address of the device and copy over to the given buffer.
70 // Returns 0 for success and -1 for error.
71
GetMacAddress()72 static int GetMacAddress()
73 {
74 struct ifreq interfaceRequest = {0};
75 struct ifconf interfaceConfiguration = {0};
76 char interfaceConfigurationBuffer[1024] = {0};
77
78 int inetSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
79 if (inetSocket == -1)
80 {
81 return -1;
82 }
83
84 interfaceConfiguration.ifc_len = sizeof(interfaceConfigurationBuffer);
85 interfaceConfiguration.ifc_buf = interfaceConfigurationBuffer;
86 if((ioctl(inetSocket, SIOCGIFCONF, &interfaceConfiguration)) == -1)
87 {
88 close(inetSocket);
89 return -1;
90 }
91
92 struct ifreq* intefaceRequestStart = interfaceConfiguration.ifc_req;
93 const struct ifreq* const interfaceRequestEnd = intefaceRequestStart + (interfaceConfiguration.ifc_len / sizeof(struct ifreq));
94
95 int32_t result = -1;
96
97 for (; intefaceRequestStart != interfaceRequestEnd; ++intefaceRequestStart)
98 {
99 strcpy(interfaceRequest.ifr_name, intefaceRequestStart->ifr_name);
100 if (ioctl(inetSocket, SIOCGIFFLAGS, &interfaceRequest) == 0)
101 {
102 // don't count loopback
103 if ((interfaceRequest.ifr_flags & IFF_LOOPBACK) == 0)
104 {
105 if (ioctl(inetSocket, SIOCGIFHWADDR, &interfaceRequest) == 0)
106 {
107 result = 0;
108 break;
109 }
110 }
111 }
112 else
113 {
114 break;
115 }
116 }
117
118 if (result == 0)
119 {
120 unsigned int size = deviceID.t.size <= MAC_ADDRESS_MAXIMUM_SIZE ? deviceID.t.size : MAC_ADDRESS_MAXIMUM_SIZE;
121 memcpy(deviceID.t.buffer, interfaceRequest.ifr_hwaddr.sa_data, size);
122 }
123
124 close(inetSocket);
125 return result;
126 }
127
128 // Read primary harddisk/emmc disk serial id from device and copy over to the given buffer.
129 // Returns 0 for success and -1 for error.
130
GetDiskSerialNumber()131 static int GetDiskSerialNumber()
132 {
133 struct udev *ud = NULL;
134 struct stat statbuf;
135 struct udev_device *device = NULL;
136 struct udev_list_entry *entry = NULL;
137 int result = -1;
138
139 ud = udev_new();
140 if (NULL == ud)
141 {
142 return result;
143 }
144 else
145 {
146
147 const unsigned int diskDeviceNamesSize = 2;
148 const char *diskDeviceNames[] = {
149 "/dev/sda", // primary hard disk.
150 "/dev/mmcblk0" // primary eMMC disk.
151 };
152
153 unsigned int i = 0;
154 while (i < diskDeviceNamesSize)
155 {
156 if (0 == stat(diskDeviceNames[i], &statbuf))
157 {
158 break;
159 }
160 i++;
161 }
162
163 if (i == diskDeviceNamesSize)
164 {
165 goto Cleanup;
166 }
167
168 const char blockDeviceType = 'b';
169 device = udev_device_new_from_devnum(ud, blockDeviceType, statbuf.st_rdev);
170 if (NULL == device)
171 {
172 goto Cleanup;
173 }
174 else
175 {
176 entry = udev_device_get_properties_list_entry(device);
177 while (NULL != entry)
178 {
179 if (0 == strcmp(udev_list_entry_get_name(entry),
180 "ID_SERIAL"))
181 {
182 break;
183 }
184
185 entry = udev_list_entry_get_next(entry);
186 }
187
188 if(entry == NULL)
189 {
190 goto Cleanup;
191 }
192
193 const char* serialNumber = udev_list_entry_get_value(entry);
194 size_t serialNumberLength = strlen(serialNumber);
195
196 size_t dataCopyLength = deviceID.t.size - MAC_ADDRESS_MAXIMUM_SIZE;
197 if (serialNumberLength < dataCopyLength)
198 {
199 dataCopyLength = serialNumberLength;
200 }
201
202 memcpy(deviceID.t.buffer, serialNumber, dataCopyLength);
203
204 result = 0;
205 }
206
207 Cleanup:
208 if(device)
209 {
210 udev_device_unref(device);
211 }
212
213 (void)udev_unref(ud);
214 return result;
215 }
216 }
217
218 #if defined(SIMULATION) && (SIMULATION == YES)
219 // Get device id from hardware parameters.
220 // CAUTION: Primary seeds derived from device unique IDs are guaranteed to remain the same as long as the reference
221 // implementation manufactures its NV state on the same device. Since this implementation of GetDeviceID() relies
222 // solely on publicly accessible values (storage device serial numbers and networking card MAC address), it can
223 // only be used for the simulation purposes, as it cannot be used to produce a secret value.
224 // pre-requisites - assumes that MAC address or disk device (i.e. /dev/sda or /dev/mmcblk0) present on the device.
GetDeviceID()225 TPM_RC GetDeviceID()
226 {
227 if(isDeviceIDSet == FALSE)
228 {
229 if(GetMacAddress() == 0)
230 {
231 isDeviceIDSet = TRUE;
232 }
233
234 if(GetDiskSerialNumber() == 0)
235 {
236 isDeviceIDSet = TRUE;
237 }
238
239 if(isDeviceIDSet == FALSE)
240 {
241 return TPM_RC_FAILURE;
242 }
243 }
244
245 return TPM_RC_SUCCESS;
246 }
247 #endif
248
GetSeed(UINT16 size,uint8_t * seed,const TPM2B * purpose)249 void GetSeed(UINT16 size, uint8_t *seed, const TPM2B *purpose)
250 {
251 RAND_STATE rand;
252
253 TPM_RC result = GetDeviceID();
254 if(result != TPM_RC_SUCCESS)
255 {
256 LOG_FAILURE(FATAL_ERROR_INTERNAL);
257 return;
258 }
259
260 result = DRBG_InstantiateSeeded(&rand.drbg, &deviceID.b, purpose, NULL, NULL);
261 if(result != TPM_RC_SUCCESS)
262 {
263 LOG_FAILURE(FATAL_ERROR_INTERNAL);
264 return;
265 }
266
267 if(DRBG_Generate(&rand, seed, size) == 0)
268 {
269 LOG_FAILURE(FATAL_ERROR_INTERNAL);
270 }
271 return;
272 }
273
274 void
_plat__GetEPS(UINT16 size,uint8_t * seed)275 _plat__GetEPS(
276 UINT16 size,
277 uint8_t *seed
278 )
279 {
280 // Ignore GCC warning.
281 (void)EPS_CREATION_;
282 GetSeed(size, seed, EPS_CREATION);
283 }
284
285 #endif