diff options
-rw-r--r-- | drivers/char/tpm/tpm.c | 145 |
1 files changed, 86 insertions, 59 deletions
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index 379c5d465579..187bcdaf7bf6 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c | |||
@@ -119,17 +119,57 @@ out: | |||
119 | } | 119 | } |
120 | 120 | ||
121 | #define TPM_DIGEST_SIZE 20 | 121 | #define TPM_DIGEST_SIZE 20 |
122 | #define CAP_PCR_RESULT_SIZE 18 | 122 | #define TPM_ERROR_SIZE 10 |
123 | static const u8 cap_pcr[] = { | 123 | #define TPM_RET_CODE_IDX 6 |
124 | #define TPM_GET_CAP_RET_SIZE_IDX 10 | ||
125 | #define TPM_GET_CAP_RET_UINT32_1_IDX 14 | ||
126 | #define TPM_GET_CAP_RET_UINT32_2_IDX 18 | ||
127 | #define TPM_GET_CAP_RET_UINT32_3_IDX 22 | ||
128 | #define TPM_GET_CAP_RET_UINT32_4_IDX 26 | ||
129 | |||
130 | #define TPM_CAP_IDX 13 | ||
131 | #define TPM_CAP_SUBCAP_IDX 21 | ||
132 | |||
133 | enum tpm_capabilities { | ||
134 | TPM_CAP_PROP = 5, | ||
135 | }; | ||
136 | |||
137 | enum tpm_sub_capabilities { | ||
138 | TPM_CAP_PROP_PCR = 0x1, | ||
139 | TPM_CAP_PROP_MANUFACTURER = 0x3, | ||
140 | }; | ||
141 | |||
142 | /* | ||
143 | * This is a semi generic GetCapability command for use | ||
144 | * with the capability type TPM_CAP_PROP or TPM_CAP_FLAG | ||
145 | * and their associated sub_capabilities. | ||
146 | */ | ||
147 | |||
148 | static const u8 tpm_cap[] = { | ||
124 | 0, 193, /* TPM_TAG_RQU_COMMAND */ | 149 | 0, 193, /* TPM_TAG_RQU_COMMAND */ |
125 | 0, 0, 0, 22, /* length */ | 150 | 0, 0, 0, 22, /* length */ |
126 | 0, 0, 0, 101, /* TPM_ORD_GetCapability */ | 151 | 0, 0, 0, 101, /* TPM_ORD_GetCapability */ |
127 | 0, 0, 0, 5, | 152 | 0, 0, 0, 0, /* TPM_CAP_<TYPE> */ |
128 | 0, 0, 0, 4, | 153 | 0, 0, 0, 4, /* TPM_CAP_SUB_<TYPE> size */ |
129 | 0, 0, 1, 1 | 154 | 0, 0, 1, 0 /* TPM_CAP_SUB_<TYPE> */ |
130 | }; | 155 | }; |
131 | 156 | ||
132 | #define READ_PCR_RESULT_SIZE 30 | 157 | static ssize_t transmit_cmd(struct tpm_chip *chip, u8 *data, int len, |
158 | char *desc) | ||
159 | { | ||
160 | int err; | ||
161 | |||
162 | len = tpm_transmit(chip, data, len); | ||
163 | if (len < 0) | ||
164 | return len; | ||
165 | if (len == TPM_ERROR_SIZE) { | ||
166 | err = be32_to_cpu(*((__be32 *) (data + TPM_RET_CODE_IDX))); | ||
167 | dev_dbg(chip->dev, "A TPM error (%d) occurred %s\n", err, desc); | ||
168 | return err; | ||
169 | } | ||
170 | return 0; | ||
171 | } | ||
172 | |||
133 | static const u8 pcrread[] = { | 173 | static const u8 pcrread[] = { |
134 | 0, 193, /* TPM_TAG_RQU_COMMAND */ | 174 | 0, 193, /* TPM_TAG_RQU_COMMAND */ |
135 | 0, 0, 0, 14, /* length */ | 175 | 0, 0, 0, 14, /* length */ |
@@ -140,8 +180,8 @@ static const u8 pcrread[] = { | |||
140 | ssize_t tpm_show_pcrs(struct device *dev, struct device_attribute *attr, | 180 | ssize_t tpm_show_pcrs(struct device *dev, struct device_attribute *attr, |
141 | char *buf) | 181 | char *buf) |
142 | { | 182 | { |
143 | u8 data[READ_PCR_RESULT_SIZE]; | 183 | u8 data[30]; |
144 | ssize_t len; | 184 | ssize_t rc; |
145 | int i, j, num_pcrs; | 185 | int i, j, num_pcrs; |
146 | __be32 index; | 186 | __be32 index; |
147 | char *str = buf; | 187 | char *str = buf; |
@@ -150,29 +190,24 @@ ssize_t tpm_show_pcrs(struct device *dev, struct device_attribute *attr, | |||
150 | if (chip == NULL) | 190 | if (chip == NULL) |
151 | return -ENODEV; | 191 | return -ENODEV; |
152 | 192 | ||
153 | memcpy(data, cap_pcr, sizeof(cap_pcr)); | 193 | memcpy(data, tpm_cap, sizeof(tpm_cap)); |
154 | if ((len = tpm_transmit(chip, data, sizeof(data))) | 194 | data[TPM_CAP_IDX] = TPM_CAP_PROP; |
155 | < CAP_PCR_RESULT_SIZE) { | 195 | data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_PCR; |
156 | dev_dbg(chip->dev, "A TPM error (%d) occurred " | 196 | |
157 | "attempting to determine the number of PCRS\n", | 197 | rc = transmit_cmd(chip, data, sizeof(data), |
158 | be32_to_cpu(*((__be32 *) (data + 6)))); | 198 | "attempting to determine the number of PCRS"); |
199 | if (rc) | ||
159 | return 0; | 200 | return 0; |
160 | } | ||
161 | 201 | ||
162 | num_pcrs = be32_to_cpu(*((__be32 *) (data + 14))); | 202 | num_pcrs = be32_to_cpu(*((__be32 *) (data + 14))); |
163 | |||
164 | for (i = 0; i < num_pcrs; i++) { | 203 | for (i = 0; i < num_pcrs; i++) { |
165 | memcpy(data, pcrread, sizeof(pcrread)); | 204 | memcpy(data, pcrread, sizeof(pcrread)); |
166 | index = cpu_to_be32(i); | 205 | index = cpu_to_be32(i); |
167 | memcpy(data + 10, &index, 4); | 206 | memcpy(data + 10, &index, 4); |
168 | if ((len = tpm_transmit(chip, data, sizeof(data))) | 207 | rc = transmit_cmd(chip, data, sizeof(data), |
169 | < READ_PCR_RESULT_SIZE){ | 208 | "attempting to read a PCR"); |
170 | dev_dbg(chip->dev, "A TPM error (%d) occurred" | 209 | if (rc) |
171 | " attempting to read PCR %d of %d\n", | ||
172 | be32_to_cpu(*((__be32 *) (data + 6))), | ||
173 | i, num_pcrs); | ||
174 | goto out; | 210 | goto out; |
175 | } | ||
176 | str += sprintf(str, "PCR-%02d: ", i); | 211 | str += sprintf(str, "PCR-%02d: ", i); |
177 | for (j = 0; j < TPM_DIGEST_SIZE; j++) | 212 | for (j = 0; j < TPM_DIGEST_SIZE; j++) |
178 | str += sprintf(str, "%02X ", *(data + 10 + j)); | 213 | str += sprintf(str, "%02X ", *(data + 10 + j)); |
@@ -194,7 +229,7 @@ ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr, | |||
194 | char *buf) | 229 | char *buf) |
195 | { | 230 | { |
196 | u8 *data; | 231 | u8 *data; |
197 | ssize_t len; | 232 | ssize_t err; |
198 | int i, rc; | 233 | int i, rc; |
199 | char *str = buf; | 234 | char *str = buf; |
200 | 235 | ||
@@ -208,14 +243,10 @@ ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr, | |||
208 | 243 | ||
209 | memcpy(data, readpubek, sizeof(readpubek)); | 244 | memcpy(data, readpubek, sizeof(readpubek)); |
210 | 245 | ||
211 | if ((len = tpm_transmit(chip, data, READ_PUBEK_RESULT_SIZE)) < | 246 | err = transmit_cmd(chip, data, READ_PUBEK_RESULT_SIZE, |
212 | READ_PUBEK_RESULT_SIZE) { | 247 | "attempting to read the PUBEK"); |
213 | dev_dbg(chip->dev, "A TPM error (%d) occurred " | 248 | if (err) |
214 | "attempting to read the PUBEK\n", | ||
215 | be32_to_cpu(*((__be32 *) (data + 6)))); | ||
216 | rc = 0; | ||
217 | goto out; | 249 | goto out; |
218 | } | ||
219 | 250 | ||
220 | /* | 251 | /* |
221 | ignore header 10 bytes | 252 | ignore header 10 bytes |
@@ -245,63 +276,59 @@ ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr, | |||
245 | if ((i + 1) % 16 == 0) | 276 | if ((i + 1) % 16 == 0) |
246 | str += sprintf(str, "\n"); | 277 | str += sprintf(str, "\n"); |
247 | } | 278 | } |
248 | rc = str - buf; | ||
249 | out: | 279 | out: |
280 | rc = str - buf; | ||
250 | kfree(data); | 281 | kfree(data); |
251 | return rc; | 282 | return rc; |
252 | } | 283 | } |
253 | EXPORT_SYMBOL_GPL(tpm_show_pubek); | 284 | EXPORT_SYMBOL_GPL(tpm_show_pubek); |
254 | 285 | ||
255 | #define CAP_VER_RESULT_SIZE 18 | 286 | #define CAP_VERSION_1_1 6 |
287 | #define CAP_VERSION_IDX 13 | ||
256 | static const u8 cap_version[] = { | 288 | static const u8 cap_version[] = { |
257 | 0, 193, /* TPM_TAG_RQU_COMMAND */ | 289 | 0, 193, /* TPM_TAG_RQU_COMMAND */ |
258 | 0, 0, 0, 18, /* length */ | 290 | 0, 0, 0, 18, /* length */ |
259 | 0, 0, 0, 101, /* TPM_ORD_GetCapability */ | 291 | 0, 0, 0, 101, /* TPM_ORD_GetCapability */ |
260 | 0, 0, 0, 6, | 292 | 0, 0, 0, 0, |
261 | 0, 0, 0, 0 | 293 | 0, 0, 0, 0 |
262 | }; | 294 | }; |
263 | 295 | ||
264 | #define CAP_MANUFACTURER_RESULT_SIZE 18 | ||
265 | static const u8 cap_manufacturer[] = { | ||
266 | 0, 193, /* TPM_TAG_RQU_COMMAND */ | ||
267 | 0, 0, 0, 22, /* length */ | ||
268 | 0, 0, 0, 101, /* TPM_ORD_GetCapability */ | ||
269 | 0, 0, 0, 5, | ||
270 | 0, 0, 0, 4, | ||
271 | 0, 0, 1, 3 | ||
272 | }; | ||
273 | |||
274 | ssize_t tpm_show_caps(struct device *dev, struct device_attribute *attr, | 296 | ssize_t tpm_show_caps(struct device *dev, struct device_attribute *attr, |
275 | char *buf) | 297 | char *buf) |
276 | { | 298 | { |
277 | u8 data[sizeof(cap_manufacturer)]; | 299 | u8 data[30]; |
278 | ssize_t len; | 300 | ssize_t rc; |
279 | char *str = buf; | 301 | char *str = buf; |
280 | 302 | ||
281 | struct tpm_chip *chip = dev_get_drvdata(dev); | 303 | struct tpm_chip *chip = dev_get_drvdata(dev); |
282 | if (chip == NULL) | 304 | if (chip == NULL) |
283 | return -ENODEV; | 305 | return -ENODEV; |
284 | 306 | ||
285 | memcpy(data, cap_manufacturer, sizeof(cap_manufacturer)); | 307 | memcpy(data, tpm_cap, sizeof(tpm_cap)); |
308 | data[TPM_CAP_IDX] = TPM_CAP_PROP; | ||
309 | data[TPM_CAP_SUBCAP_IDX] = TPM_CAP_PROP_MANUFACTURER; | ||
286 | 310 | ||
287 | if ((len = tpm_transmit(chip, data, sizeof(data))) < | 311 | rc = transmit_cmd(chip, data, sizeof(data), |
288 | CAP_MANUFACTURER_RESULT_SIZE) | 312 | "attempting to determine the manufacturer"); |
289 | return len; | 313 | if (rc) |
314 | return 0; | ||
290 | 315 | ||
291 | str += sprintf(str, "Manufacturer: 0x%x\n", | 316 | str += sprintf(str, "Manufacturer: 0x%x\n", |
292 | be32_to_cpu(*((__be32 *) (data + 14)))); | 317 | be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_1_IDX)))); |
293 | 318 | ||
294 | memcpy(data, cap_version, sizeof(cap_version)); | 319 | memcpy(data, cap_version, sizeof(cap_version)); |
320 | data[CAP_VERSION_IDX] = CAP_VERSION_1_1; | ||
321 | rc = transmit_cmd(chip, data, sizeof(data), | ||
322 | "attempting to determine the 1.1 version"); | ||
323 | if (rc) | ||
324 | goto out; | ||
295 | 325 | ||
296 | if ((len = tpm_transmit(chip, data, sizeof(data))) < | 326 | str += sprintf(str, |
297 | CAP_VER_RESULT_SIZE) | 327 | "TCG version: %d.%d\nFirmware version: %d.%d\n", |
298 | return len; | 328 | (int) data[14], (int) data[15], (int) data[16], |
299 | 329 | (int) data[17]); | |
300 | str += | ||
301 | sprintf(str, "TCG version: %d.%d\nFirmware version: %d.%d\n", | ||
302 | (int) data[14], (int) data[15], (int) data[16], | ||
303 | (int) data[17]); | ||
304 | 330 | ||
331 | out: | ||
305 | return str - buf; | 332 | return str - buf; |
306 | } | 333 | } |
307 | EXPORT_SYMBOL_GPL(tpm_show_caps); | 334 | EXPORT_SYMBOL_GPL(tpm_show_caps); |