]> git.proxmox.com Git - swtpm.git/blame - src/swtpm_setup/swtpm_setup.c
tests: Support filenames with spaces in some functions
[swtpm.git] / src / swtpm_setup / swtpm_setup.c
CommitLineData
c125e34b
SB
1/* SPDX-License-Identifier: BSD-3-Clause */
2/*
3 * swtpm_setup.c: Tool to simulate TPM 1.2 & TPM 2 manufacturing
4 *
5 * Author: Stefan Berger, stefanb@linux.ibm.com
6 *
7 * Copyright (c) IBM Corporation, 2021
8 */
9
10#include "config.h"
11
12#include <errno.h>
13#include <getopt.h>
14#include <grp.h>
15#include <limits.h>
16#include <pwd.h>
17#include <stdlib.h>
18#include <stdio.h>
19#include <string.h>
20#include <unistd.h>
21#include <sys/stat.h>
22#include <fcntl.h>
23#include <sys/types.h>
d766b58d 24#include <sys/wait.h>
c125e34b
SB
25
26#include <glib.h>
27#include <glib/gstdio.h>
28#include <glib/gprintf.h>
29
30#include <glib-object.h>
31#include <json-glib/json-glib.h>
32
f2aa3274
SB
33#include <libtpms/tpm_nvfilename.h>
34
c125e34b
SB
35#include "swtpm.h"
36#include "swtpm_setup_conf.h"
37#include "swtpm_setup_utils.h"
38#include "swtpm_utils.h"
39
40#include <openssl/sha.h>
41
42/* default values for passwords */
43#define DEFAULT_OWNER_PASSWORD "ooo"
44#define DEFAULT_SRK_PASSWORD "sss"
45
8422d068
SB
46#define SETUP_CREATE_EK_F (1 << 0)
47#define SETUP_TAKEOWN_F (1 << 1)
48#define SETUP_EK_CERT_F (1 << 2)
49#define SETUP_PLATFORM_CERT_F (1 << 3)
50#define SETUP_LOCK_NVRAM_F (1 << 4)
51#define SETUP_SRKPASS_ZEROS_F (1 << 5)
52#define SETUP_OWNERPASS_ZEROS_F (1 << 6)
53#define SETUP_STATE_OVERWRITE_F (1 << 7)
54#define SETUP_STATE_NOT_OVERWRITE_F (1 << 8)
55#define SETUP_TPM2_F (1 << 9)
56#define SETUP_ALLOW_SIGNING_F (1 << 10)
57#define SETUP_TPM2_ECC_F (1 << 11)
58#define SETUP_CREATE_SPK_F (1 << 12)
59#define SETUP_DISPLAY_RESULTS_F (1 << 13)
60#define SETUP_DECRYPTION_F (1 << 14)
61#define SETUP_WRITE_EK_CERT_FILES_F (1 << 15)
c125e34b
SB
62
63/* default configuration file */
64#define SWTPM_SETUP_CONF "swtpm_setup.conf"
65
c125e34b
SB
66/* Default logging goes to stderr */
67gchar *gl_LOGFILE = NULL;
68
69#define DEFAULT_RSA_KEYSIZE 2048
70
71
72static const struct flag_to_certfile {
73 unsigned long flag;
74 const char *filename;
75 const char *type;
76} flags_to_certfiles[] = {
78559edd 77 {.flag = SETUP_EK_CERT_F , .filename = "ek.cert", .type = "ek" },
c125e34b
SB
78 {.flag = SETUP_PLATFORM_CERT_F, .filename = "platform.cert", .type = "platform" },
79 {.flag = 0, .filename = NULL, .type = NULL},
80};
81
82/* initialize the path of the config_file */
83static int init(gchar **config_file)
84{
874c3338
SB
85 const gchar *configdir = g_get_user_config_dir();
86
87 *config_file = g_build_filename(configdir, SWTPM_SETUP_CONF, NULL);
88 if (access(*config_file, R_OK) != 0) {
89 g_free(*config_file);
90 *config_file = g_build_filename(SYSCONFDIR, SWTPM_SETUP_CONF, NULL);
c125e34b 91 }
c125e34b 92
874c3338 93 return 0;
c125e34b
SB
94}
95
96/* Get the spec and attributes parameters from swtpm */
97static int tpm_get_specs_and_attributes(struct swtpm *swtpm, gchar ***params)
98{
99 int ret;
100 g_autofree gchar *json = NULL;
101 JsonParser *jp = NULL;
102 GError *error = NULL;
103 JsonReader *jr = NULL;
104 JsonNode *root;
105 static const struct parse_rule {
106 const char *node1;
107 const char *node2;
108 gboolean is_int;
109 const char *optname;
110 } parser_rules[7] = {
111 {"TPMSpecification", "family", FALSE, "--tpm-spec-family"},
112 {"TPMSpecification", "level", TRUE, "--tpm-spec-level"},
113 {"TPMSpecification", "revision", TRUE, "--tpm-spec-revision"},
114 {"TPMAttributes", "manufacturer", FALSE, "--tpm-manufacturer"},
115 {"TPMAttributes", "model", FALSE, "--tpm-model"},
116 {"TPMAttributes", "version", FALSE, "--tpm-version"},
117 {NULL, NULL, FALSE, NULL},
118 };
119 size_t idx;
120
121 ret = swtpm->cops->ctrl_get_tpm_specs_and_attrs(swtpm, &json);
122 if (ret != 0) {
123 logerr(gl_LOGFILE, "Could not get the TPM spec and attribute parameters.\n");
124 return 1;
125 }
126
127 jp = json_parser_new();
128
129 if (!json_parser_load_from_data(jp, json, -1, &error)) {
130 logerr(gl_LOGFILE, "JSON parser failed: %s\n", error->message);
131 g_error_free(error);
132 goto error;
133 }
134
135 *params = NULL;
136 root = json_parser_get_root(jp);
137
138 for (idx = 0; parser_rules[idx].node1 != NULL; idx++) {
139 jr = json_reader_new(root);
140 if (json_reader_read_member(jr, parser_rules[idx].node1) &&
141 json_reader_read_member(jr, parser_rules[idx].node2)) {
142 gchar *str;
143
144 if (parser_rules[idx].is_int)
145 str = g_strdup_printf("%ld", (long)json_reader_get_int_value(jr));
146 else
147 str = g_strdup(json_reader_get_string_value(jr));
148
149 *params = concat_arrays(*params,
150 (gchar*[]){
151 g_strdup(parser_rules[idx].optname),
152 str,
153 NULL
154 }, TRUE);
155 } else {
156 logerr(gl_LOGFILE, "Could not find [%s][%s] in '%s'\n",
157 parser_rules[idx].node1, parser_rules[idx].node2, json);
158 ret = 1;
159 break;
160 }
161 g_object_unref(jr);
162 jr = NULL;
163 }
164
165 if (ret) {
166 g_strfreev(*params);
167 *params = NULL;
168 g_object_unref(jr);
169 }
170error:
171 g_object_unref(jp);
172
173 return ret;
174}
175
176/* Call an external tool to create the certificates */
177static int call_create_certs(unsigned long flags, const gchar *configfile, const gchar *certsdir,
178 const gchar *ekparam, const gchar *vmid, struct swtpm *swtpm)
179{
180 gchar **config_file_lines = NULL; /* must free */
181 g_autofree gchar *create_certs_tool = NULL;
182 g_autofree gchar *create_certs_tool_config = NULL;
183 g_autofree gchar *create_certs_tool_options = NULL;
184 g_autofree gchar **cmd = NULL;
185 gchar **params = NULL; /* must free */
186 g_autofree gchar *prgname = NULL;
187 gboolean success;
188 gint exit_status;
189 size_t idx, j;
190 gchar *s;
191 int ret;
192
193 ret = tpm_get_specs_and_attributes(swtpm, &params);
194 if (ret != 0)
195 goto error;
196
197 ret = read_file_lines(configfile, &config_file_lines);
198 if (ret != 0)
199 goto error;
200
201 create_certs_tool = get_config_value(config_file_lines, "create_certs_tool");
202 create_certs_tool_config = get_config_value(config_file_lines, "create_certs_tool_config");
203 create_certs_tool_options = get_config_value(config_file_lines, "create_certs_tool_options");
204
205 ret = 0;
206
207 if (create_certs_tool != NULL) {
208 g_autofree gchar *create_certs_tool_path = g_find_program_in_path(create_certs_tool);
209 if (create_certs_tool_path == NULL) {
210 logerr(gl_LOGFILE, "Could not find %s in PATH.\n", create_certs_tool);
211 ret = 1;
212 goto error;
213 }
214
215 if (flags & SETUP_TPM2_F) {
216 params = concat_arrays(params,
217 (gchar*[]){
218 g_strdup("--tpm2"),
219 NULL
220 }, TRUE);
221 }
222 cmd = concat_arrays((gchar*[]) {
223 create_certs_tool_path,
224 "--type", "_", /* '_' must be at index '2' ! */
225 "--ek", (gchar *)ekparam,
226 "--dir", (gchar *)certsdir,
227 NULL
228 }, NULL, FALSE);
229 if (gl_LOGFILE != NULL)
230 cmd = concat_arrays(cmd, (gchar*[]){"--logfile", (gchar *)gl_LOGFILE, NULL}, TRUE);
231 if (vmid != NULL)
232 cmd = concat_arrays(cmd, (gchar*[]){"--vmid", (gchar *)vmid, NULL}, TRUE);
233 cmd = concat_arrays(cmd, params, TRUE);
234 if (create_certs_tool_config != NULL)
235 cmd = concat_arrays(cmd, (gchar*[]){"--configfile", create_certs_tool_config, NULL}, TRUE);
236 if (create_certs_tool_options != NULL)
237 cmd = concat_arrays(cmd, (gchar*[]){"--optsfile", create_certs_tool_options, NULL}, TRUE);
238
239 s = g_strrstr(create_certs_tool, G_DIR_SEPARATOR_S);
240 if (s)
241 prgname = strdup(&s[1]);
242 else
243 prgname = strdup(create_certs_tool);
244
245 for (idx = 0; flags_to_certfiles[idx].filename != NULL; idx++) {
246 if (flags & flags_to_certfiles[idx].flag) {
247 g_autofree gchar *standard_output = NULL;
c40fceb3 248 g_autofree gchar *standard_error = NULL;
c125e34b
SB
249 GError *error = NULL;
250 gchar **lines;
251
252 cmd[2] = (gchar *)flags_to_certfiles[idx].type; /* replaces the "_" above */
253
254 s = g_strjoinv(" ", cmd);
255 logit(gl_LOGFILE, " Invoking %s\n", s);
256 g_free(s);
257
c40fceb3
SB
258 success = g_spawn_sync(NULL, cmd, NULL, 0, NULL, NULL,
259 &standard_output, &standard_error, &exit_status, &error);
c125e34b
SB
260 if (!success) {
261 logerr(gl_LOGFILE, "An error occurred running %s: %s\n",
262 create_certs_tool, error->message);
263 g_error_free(error);
264 ret = 1;
265 break;
266 } else if (exit_status != 0) {
267 logerr(gl_LOGFILE, "%s exit with status %d: %s\n",
c40fceb3 268 prgname, WEXITSTATUS(exit_status), standard_error);
c125e34b
SB
269 ret = 1;
270 break;
271 }
272
273 lines = g_strsplit(standard_output, "\n", -1);
274 for (j = 0; lines[j] != NULL; j++) {
275 if (strlen(lines[j]) > 0)
276 logit(gl_LOGFILE, "%s: %s\n", prgname, lines[j]);
277 }
278 g_strfreev(lines);
279
280 g_free(standard_output);
281 standard_output = NULL;
c40fceb3
SB
282 g_free(standard_error);
283 standard_error = NULL;
c125e34b
SB
284 }
285 }
286 }
287
288error:
289 g_strfreev(config_file_lines);
290 g_strfreev(params);
291
292 return ret;
293}
294
78559edd
SB
295static char *create_ek_certfile_name(const gchar *user_certsdir, const gchar *key_description)
296{
297 g_autofree gchar *filename = g_strdup_printf("ek-%s.crt", key_description);
298
299 return g_strjoin(G_DIR_SEPARATOR_S, user_certsdir, filename, NULL);
300}
301
302/*
303 * Remove the cert file unless the user wants a copy of it (EK only).
304 */
305static int certfile_move_or_delete(unsigned long flags, gboolean is_ek, const gchar *certfile,
306 const gchar *user_certsdir, const gchar *key_description)
307{
308 g_autofree gchar *content = NULL;
309 g_autofree gchar *cf = NULL;
310 gsize content_length;
311 GError *error = NULL;
312 size_t offset = 0;
313
314 if (is_ek && (flags & SETUP_WRITE_EK_CERT_FILES_F) && user_certsdir != NULL) {
315 if (!g_file_get_contents(certfile, &content, &content_length, &error))
316 goto error;
317
318 cf = create_ek_certfile_name(user_certsdir, key_description);
319 if (!(flags & SETUP_TPM2_F)) {
320 /* A TPM 1.2 certificate has a 7 byte header at the beginning
321 * that we now remove */
322 if (content_length >= 8)
323 offset = 7;
324 }
325 if (!g_file_set_contents(cf, &content[offset], content_length - offset,
326 &error))
327 goto error;
328 if (g_chmod(cf, S_IRUSR | S_IWUSR | S_IRGRP) < 0) {
329 logerr(gl_LOGFILE, "Failed to chmod file '%s': %s\n", cf, strerror(errno));
330 goto error_unlink;
331 }
332 }
333 unlink(certfile);
334
335 return 0;
336
337error:
338 logerr(gl_LOGFILE, "%s\n", error->message);
339 g_error_free(error);
340
341error_unlink:
342 unlink(certfile);
343
344 return 1;
345}
346
c125e34b
SB
347/* Create EK and certificate for a TPM 2 */
348static int tpm2_create_ek_and_cert(unsigned long flags, const gchar *config_file,
349 const gchar *certsdir, const gchar *vmid,
78559edd
SB
350 unsigned int rsa_keysize, struct swtpm2 *swtpm2,
351 const gchar *user_certsdir)
c125e34b
SB
352{
353 g_autofree gchar *filecontent = NULL;
354 size_t filecontent_len;
355 g_autofree gchar *certfile = NULL;
356 g_autofree gchar *ekparam = NULL;
78559edd 357 const char *key_description;
c125e34b
SB
358 size_t idx;
359 int ret;
360
361 if (flags & SETUP_CREATE_EK_F) {
362 ret = swtpm2->ops->create_ek(&swtpm2->swtpm, !!(flags & SETUP_TPM2_ECC_F), rsa_keysize,
363 !!(flags & SETUP_ALLOW_SIGNING_F),
364 !!(flags & SETUP_DECRYPTION_F),
365 !!(flags & SETUP_LOCK_NVRAM_F),
78559edd 366 &ekparam, &key_description);
c125e34b
SB
367 if (ret != 0)
368 return 1;
369 }
370
371 if (flags & (SETUP_EK_CERT_F | SETUP_PLATFORM_CERT_F)) {
372 ret = call_create_certs(flags, config_file, certsdir, ekparam, vmid, &swtpm2->swtpm);
373 if (ret != 0)
374 return 1;
375
376 for (idx = 0; flags_to_certfiles[idx].filename; idx++) {
377 if (flags & flags_to_certfiles[idx].flag) {
378 g_free(certfile);
379 certfile = g_strjoin(G_DIR_SEPARATOR_S, certsdir, flags_to_certfiles[idx].filename, NULL);
380
381 g_free(filecontent);
382 filecontent = NULL;
383 ret = read_file(certfile, &filecontent, &filecontent_len);
384 if (ret != 0)
385 return 1;
386
387 if (flags_to_certfiles[idx].flag == SETUP_EK_CERT_F) {
388 ret = swtpm2->ops->write_ek_cert_nvram(&swtpm2->swtpm,
389 !!(flags & SETUP_TPM2_ECC_F), rsa_keysize,
390 !!(flags & SETUP_LOCK_NVRAM_F),
391 (const unsigned char*)filecontent, filecontent_len);
392 } else {
393 ret = swtpm2->ops->write_platform_cert_nvram(&swtpm2->swtpm,
394 !!(flags & SETUP_LOCK_NVRAM_F),
395 (const unsigned char *)filecontent, filecontent_len);
396 }
c125e34b 397
78559edd
SB
398 if (ret != 0) {
399 unlink(certfile);
400 return 1;
401 }
402
403 if (certfile_move_or_delete(flags, !!(flags_to_certfiles[idx].flag & SETUP_EK_CERT_F),
404 certfile, user_certsdir, key_description) != 0)
c125e34b
SB
405 return 1;
406 }
407 }
408 }
409
410 return 0;
411}
412
413/* Create endorsement keys and certificates for a TPM 2 */
414static int tpm2_create_eks_and_certs(unsigned long flags, const gchar *config_file,
415 const gchar *certsdir, const gchar *vmid,
78559edd
SB
416 unsigned int rsa_keysize, struct swtpm2 *swtpm2,
417 const gchar *user_certsdir)
c125e34b
SB
418{
419 int ret;
420
421 /* 1st key will be RSA */
422 flags = flags & ~SETUP_TPM2_ECC_F;
78559edd
SB
423 ret = tpm2_create_ek_and_cert(flags, config_file, certsdir, vmid, rsa_keysize, swtpm2,
424 user_certsdir);
c125e34b
SB
425 if (ret != 0)
426 return 1;
427
428 /* 2nd key will be an ECC; no more platform cert */
429 flags = (flags & ~SETUP_PLATFORM_CERT_F) | SETUP_TPM2_ECC_F;
78559edd
SB
430 return tpm2_create_ek_and_cert(flags, config_file, certsdir, vmid, rsa_keysize, swtpm2,
431 user_certsdir);
c125e34b
SB
432}
433
a5cc0bf6
SB
434/* Get the default PCR banks from the config file and if nothing can
435 be found there use the DEFAULT_PCR_BANKS #define.
436 */
437static gchar *get_default_pcr_banks(const gchar *config_file)
438{
439 g_auto(GStrv) config_file_lines = NULL;
440 gchar *pcr_banks;
441 int ret;
442
443 ret = read_file_lines(config_file, &config_file_lines);
444 if (ret != 0)
445 return NULL;
446
447 pcr_banks = get_config_value(config_file_lines, "active_pcr_banks");
448 if (pcr_banks)
449 g_strstrip(pcr_banks);
450 if (pcr_banks == NULL || strlen(pcr_banks) == 0) {
451 g_free(pcr_banks);
452 pcr_banks = g_strdup(DEFAULT_PCR_BANKS);
453 }
454 return pcr_banks;
455}
456
87755f8c
SB
457/* Activate the given list of PCR banks. If pcr_banks is '-' then leave
458 * the configuration as-is.
459 */
460static int tpm2_activate_pcr_banks(struct swtpm2 *swtpm2,
461 const gchar *pcr_banks)
462{
463 g_autofree gchar *active_pcr_banks_join = NULL;
464 g_autofree gchar *all_pcr_banks_join = NULL;
465 g_auto(GStrv) active_pcr_banks = NULL;
466 g_auto(GStrv) all_pcr_banks = NULL;
467 g_auto(GStrv) pcr_banks_l = NULL;
468 struct swtpm *swtpm = &swtpm2->swtpm;
469 int ret = 0;
470
471 if (g_str_equal(pcr_banks, "-"))
472 return 0;
473
474 ret = swtpm2->ops->get_all_pcr_banks(swtpm, &all_pcr_banks);
475 if (ret != 0)
476 return ret;
477
478 pcr_banks_l = g_strsplit(pcr_banks, ",", -1);
479 ret = swtpm2->ops->set_active_pcr_banks(swtpm, pcr_banks_l, all_pcr_banks,
480 &active_pcr_banks);
481 if (ret != 0)
482 return ret;
483
484 active_pcr_banks_join = g_strjoinv(",", active_pcr_banks);
485 all_pcr_banks_join = g_strjoinv(",", all_pcr_banks);
486 logit(gl_LOGFILE, "Successfully activated PCR banks %s among %s.\n",
487 active_pcr_banks_join, all_pcr_banks_join);
488
489 return 0;
490}
491
c125e34b
SB
492/* Simulate manufacturing a TPM 2: create keys and certificates */
493static int init_tpm2(unsigned long flags, gchar **swtpm_prg_l, const gchar *config_file,
494 const gchar *tpm2_state_path, const gchar *vmid, const gchar *pcr_banks,
495 const gchar *swtpm_keyopt, int *fds_to_pass, size_t n_fds_to_pass,
20ca1eb3
ET
496 unsigned int rsa_keysize, const gchar *certsdir,
497 const gchar *user_certsdir)
c125e34b 498{
c125e34b
SB
499 struct swtpm2 *swtpm2;
500 struct swtpm *swtpm;
501 int ret;
502
503 swtpm2 = swtpm2_new(swtpm_prg_l, tpm2_state_path, swtpm_keyopt, gl_LOGFILE,
504 fds_to_pass, n_fds_to_pass);
505 if (swtpm2 == NULL)
506 return 1;
507 swtpm = &swtpm2->swtpm;
508
509 ret = swtpm->cops->start(swtpm);
510 if (ret != 0) {
511 logerr(gl_LOGFILE, "Could not start the TPM 2.\n");
512 goto error;
513 }
514
515 if ((flags & SETUP_CREATE_SPK_F)) {
516 ret = swtpm2->ops->create_spk(swtpm, !!(flags & SETUP_TPM2_ECC_F), rsa_keysize);
517 if (ret != 0)
518 goto destroy;
519 }
520
78559edd
SB
521 ret = tpm2_create_eks_and_certs(flags, config_file, certsdir, vmid, rsa_keysize, swtpm2,
522 user_certsdir);
c125e34b
SB
523 if (ret != 0)
524 goto destroy;
525
87755f8c
SB
526 ret = tpm2_activate_pcr_banks(swtpm2, pcr_banks);
527 if (ret != 0)
528 goto destroy;
c125e34b
SB
529
530 ret = swtpm2->ops->shutdown(swtpm);
531
532destroy:
533 swtpm->cops->destroy(swtpm);
534
535error:
536 swtpm_free(swtpm);
537
538 return ret;
539}
540
541/* Create the owner password digest */
542static void tpm12_get_ownerpass_digest(unsigned long flags, const gchar *ownerpass,
543 unsigned char ownerpass_digest[SHA_DIGEST_LENGTH])
544{
545 const gchar zeros[SHA_DIGEST_LENGTH]= {0, };
546 size_t len;
547
548 if (ownerpass == NULL) {
549 if (flags & SETUP_OWNERPASS_ZEROS_F) {
550 ownerpass = zeros;
551 len = sizeof(zeros);
552 } else {
553 ownerpass = DEFAULT_OWNER_PASSWORD;
554 len = strlen(ownerpass);
555 }
556 } else {
557 len = strlen(ownerpass);
558 }
559 SHA1((const unsigned char *)ownerpass, len, ownerpass_digest);
560}
561
562/* Create the SRK password digest */
563static void tpm12_get_srkpass_digest(unsigned long flags, const gchar *srkpass,
564 unsigned char srkpass_digest[SHA_DIGEST_LENGTH])
565{
566 const gchar zeros[SHA_DIGEST_LENGTH]= {0, };
567 size_t len;
568
569 if (srkpass == NULL) {
570 if (flags & SETUP_SRKPASS_ZEROS_F) {
571 srkpass = zeros;
572 len = sizeof(zeros);
573 } else {
574 srkpass = DEFAULT_SRK_PASSWORD;
575 len = strlen(srkpass);
576 }
577 } else {
578 len = strlen(srkpass);
579 }
580 SHA1((const unsigned char *)srkpass, len, srkpass_digest);
581}
582
583/* Take ownership of a TPM 1.2 */
584static int tpm12_take_ownership(unsigned long flags, const gchar *ownerpass,
585 const gchar *srkpass, gchar *pubek, size_t pubek_len,
586 struct swtpm12 *swtpm12)
587{
588 unsigned char ownerpass_digest[SHA_DIGEST_LENGTH];
589 unsigned char srkpass_digest[SHA_DIGEST_LENGTH];
590
591 tpm12_get_ownerpass_digest(flags, ownerpass, ownerpass_digest);
592 tpm12_get_srkpass_digest(flags, srkpass, srkpass_digest);
593
594 return swtpm12->ops->take_ownership(&swtpm12->swtpm, ownerpass_digest, srkpass_digest,
595 (const unsigned char *)pubek, pubek_len);
596}
597
598/* Create the certificates for a TPM 1.2 */
599static int tpm12_create_certs(unsigned long flags, const gchar *config_file,
600 const gchar *certsdir, const gchar *ekparam,
78559edd
SB
601 const gchar *vmid, struct swtpm12 *swtpm12,
602 const gchar *user_certsdir)
c125e34b
SB
603{
604 g_autofree gchar *filecontent = NULL;
605 g_autofree gchar *certfile = NULL;
606 gsize filecontent_len;
607 size_t idx;
608 int ret;
609
610 ret = call_create_certs(flags, config_file, certsdir, ekparam, vmid, &swtpm12->swtpm);
611 if (ret != 0)
612 return 1;
613
614 for (idx = 0; flags_to_certfiles[idx].filename; idx++) {
615 if (flags & flags_to_certfiles[idx].flag) {
616 g_free(certfile);
617 certfile = g_strjoin(G_DIR_SEPARATOR_S, certsdir,
618 flags_to_certfiles[idx].filename, NULL);
619
620 g_free(filecontent);
621 filecontent = NULL;
622 ret = read_file(certfile, &filecontent, &filecontent_len);
623 if (ret != 0)
624 return 1;
625
626 if (flags_to_certfiles[idx].flag == SETUP_EK_CERT_F) {
627 ret = swtpm12->ops->write_ek_cert_nvram(&swtpm12->swtpm,
628 (const unsigned char*)filecontent, filecontent_len);
629 if (ret == 0)
630 logit(gl_LOGFILE, "Successfully created NVRAM area for EK certificate.\n");
631 } else {
632 ret = swtpm12->ops->write_platform_cert_nvram(&swtpm12->swtpm,
633 (const unsigned char*)filecontent, filecontent_len);
634 if (ret == 0)
635 logit(gl_LOGFILE, "Successfully created NVRAM area for Platform certificate.\n");
636 }
78559edd
SB
637
638 if (ret != 0) {
639 unlink(certfile);
640 return 1;
641 }
642
643 if (certfile_move_or_delete(flags, !!(flags_to_certfiles[idx].flag & SETUP_EK_CERT_F),
644 certfile, user_certsdir, "rsa2048") != 0)
c125e34b
SB
645 return 1;
646 }
647 }
648
649 return 0;
650}
651
652/* Simulate manufacturing a TPM 1.2: create keys and certificate and possibly take ownership */
653static int init_tpm(unsigned long flags, gchar **swtpm_prg_l, const gchar *config_file,
654 const gchar *tpm_state_path, const gchar *ownerpass, const gchar *srkpass,
655 const gchar *vmid, const gchar *swtpm_keyopt,
20ca1eb3
ET
656 int *fds_to_pass, size_t n_fds_to_pass, const gchar *certsdir,
657 const gchar *user_certsdir)
c125e34b 658{
c125e34b
SB
659 struct swtpm12 *swtpm12;
660 struct swtpm *swtpm;
661 g_autofree gchar *pubek = NULL;
662 size_t pubek_len;
663 int ret = 1;
664
665 swtpm12 = swtpm12_new(swtpm_prg_l, tpm_state_path, swtpm_keyopt, gl_LOGFILE,
666 fds_to_pass, n_fds_to_pass);
667 if (swtpm12 == NULL)
668 return 1;
669 swtpm = &swtpm12->swtpm;
670
671 ret = swtpm->cops->start(swtpm);
672 if (ret != 0) {
673 logerr(gl_LOGFILE, "Could not start the TPM 1.2.\n");
674 goto error;
675 }
676
677 ret = swtpm12->ops->run_swtpm_bios(swtpm);
678 if (ret != 0)
679 goto destroy;
680
681 if ((flags & SETUP_CREATE_EK_F)) {
682 ret = swtpm12->ops->create_endorsement_key_pair(swtpm, &pubek, &pubek_len);
683 if (ret != 0)
684 goto destroy;
685
686 logit(gl_LOGFILE, "Successfully created EK.\n");
687
688 /* can only take owernship if created an EK */
689 if ((flags & SETUP_TAKEOWN_F)) {
690 ret = tpm12_take_ownership(flags, ownerpass, srkpass, pubek, pubek_len, swtpm12);
691 if (ret != 0)
692 goto destroy;
693
694 logit(gl_LOGFILE, "Successfully took ownership of the TPM.\n");
695 }
696
697 /* can only create EK cert if created an EK */
698 if ((flags & SETUP_EK_CERT_F)) {
699 g_autofree gchar *ekparam = print_as_hex((unsigned char *)pubek, pubek_len);
700
78559edd
SB
701 ret = tpm12_create_certs(flags, config_file, certsdir, ekparam, vmid, swtpm12,
702 user_certsdir);
c125e34b
SB
703 if (ret != 0)
704 goto destroy;
705 }
706 }
707
708 if ((flags & SETUP_LOCK_NVRAM_F)) {
709 ret = swtpm12->ops->nv_lock(swtpm);
710 if (ret == 0)
711 logit(gl_LOGFILE, "Successfully locked NVRAM access.\n");
712 }
713
714destroy:
715 swtpm->cops->destroy(swtpm);
716
717error:
718 swtpm_free(swtpm);
719
720 return ret;
721}
722
723/* Check whether we are allowed to overwrite existing state.
724 * This function returns 2 if the state exists but flag is set to not to overwrite it,
725 * 0 in case we can overwrite it, 1 if the state exists.
726 */
e0d2c0ed
ET
727static int check_state_overwrite(gchar **swtpm_prg_l, unsigned int flags,
728 const char *tpm_state_path)
c125e34b 729{
e0d2c0ed
ET
730 gboolean success;
731 g_autofree gchar *standard_output = NULL;
732 int exit_status = 0;
733 g_autoptr(GError) error = NULL;
734 g_autofree gchar **argv = NULL;
81371f66 735 g_autofree gchar *statearg = g_strdup_printf("backend-uri=%s", tpm_state_path);
7b7dcbb8 736 g_autofree gchar *logop = NULL;
e0d2c0ed 737 g_autofree gchar **my_argv = NULL;
c125e34b 738
e0d2c0ed
ET
739 my_argv = concat_arrays((gchar*[]) {
740 "--print-states",
741 "--tpmstate",
81371f66 742 statearg,
e0d2c0ed
ET
743 NULL
744 }, NULL, FALSE);
745
f2aa3274 746 if (flags & SETUP_TPM2_F)
e0d2c0ed 747 my_argv = concat_arrays(my_argv, (gchar*[]) { "--tpm2", NULL }, TRUE);
c125e34b 748
7b7dcbb8
ET
749 if (gl_LOGFILE != NULL) {
750 logop = g_strdup_printf("file=%s", gl_LOGFILE);
751 my_argv = concat_arrays(my_argv, (gchar*[]){"--log", logop, NULL}, TRUE);
752 }
753
e0d2c0ed 754 argv = concat_arrays(swtpm_prg_l, my_argv, FALSE);
7b7dcbb8 755
e0d2c0ed
ET
756 success = g_spawn_sync(NULL, argv, NULL, G_SPAWN_STDERR_TO_DEV_NULL, NULL, NULL,
757 &standard_output, NULL, &exit_status, &error);
758 if (!success) {
759 logerr(gl_LOGFILE, "Could not start swtpm '%s': %s\n", swtpm_prg_l[0], error->message);
760 return 1;
761 }
762
763 if (exit_status != 0) {
764 logerr(gl_LOGFILE, "%s exit with status %d: %s\n",
765 swtpm_prg_l[0], exit_status, standard_output);
c125e34b 766 return 1;
e0d2c0ed 767 }
c125e34b 768
f2aa3274 769 if (g_strstr_len(standard_output, -1, TPM_PERMANENT_ALL_NAME) != NULL) {
e0d2c0ed 770 /* State file exists */
c125e34b
SB
771 if (flags & SETUP_STATE_NOT_OVERWRITE_F) {
772 logit(gl_LOGFILE, "Not overwriting existing state file.\n");
773 return 2;
774 }
775 if (flags & SETUP_STATE_OVERWRITE_F)
776 return 0;
f2aa3274 777 logerr(gl_LOGFILE, "Found existing TPM state '%s'.\n", TPM_PERMANENT_ALL_NAME);
c125e34b
SB
778 return 1;
779 }
780
781 return 0;
782}
783
c125e34b
SB
784static void versioninfo(void)
785{
786 printf("TPM emulator setup tool version %d.%d.%d\n",
787 SWTPM_VER_MAJOR, SWTPM_VER_MINOR, SWTPM_VER_MICRO);
788}
789
790static void usage(const char *prgname, const char *default_config_file)
791{
792 versioninfo();
793 printf(
794 "Usage: %s [options]\n"
795 "\n"
796 "The following options are supported:\n"
797 "\n"
798 "--runas <user> : Run this program under the given user's account.\n"
799 "\n"
a4555cb8
SR
800 "--tpm-state <dir>: Path where the TPM's state will be written to;\n"
801 " this is a mandatory argument. Prefix with dir:// to"
802 " use directory backend, or file:// to use linear file.\n"
c125e34b
SB
803 "\n"
804 "--tpmstate <dir> : This is an alias for --tpm-state <dir>.\n"
805 "\n"
806 "--tpm <executable>\n"
807 " : Path to the TPM executable; this is an optional argument and\n"
808 " by default 'swtpm' in the PATH is used.\n"
809 "\n"
810 "--swtpm_ioctl <executable>\n"
811 " : Path to the swtpm_ioctl executable; this is deprecated\n"
812 " argument.\n"
813 "\n"
814 "--tpm2 : Setup a TPM 2; by default a TPM 1.2 is setup.\n"
815 "\n"
816 "--createek : Create the EK; for a TPM 2 an RSA and ECC EK will be\n"
817 " created\n"
818 "\n"
819 "--allow-signing : Create an EK that can be used for signing;\n"
820 " this option requires --tpm2.\n"
821 " Note: Careful, this option will create a non-standard EK!\n"
822 "\n"
823 "--decryption : Create an EK that can be used for key encipherment;\n"
824 " this is the default unless --allow-signing is given;\n"
825 " this option requires --tpm2.\n"
826 "\n"
827 "--ecc : This option allows to create a TPM 2's ECC key as storage\n"
828 " primary key; a TPM 2 always gets an RSA and an ECC EK key.\n"
829 "\n"
830 "--take-ownership : Take ownership; this option implies --createek\n"
831 " --ownerpass <password>\n"
832 " : Provide custom owner password; default is %s\n"
833 " --owner-well-known:\n"
834 " : Use an owner password of 20 zero bytes\n"
835 " --srkpass <password>\n"
836 " : Provide custom SRK password; default is %s\n"
837 " --srk-well-known:\n"
838 " : Use an SRK password of 20 zero bytes\n"
839 "--create-ek-cert : Create an EK certificate; this implies --createek\n"
840 "\n"
841 "--create-platform-cert\n"
842 " : Create a platform certificate; this implies --create-ek-cert\n"
843 "\n"
844 "--create-spk : Create storage primary key; this requires --tpm2\n"
845 "\n"
846 "--lock-nvram : Lock NVRAM access\n"
847 "\n"
848 "--display : At the end display as much info as possible about the\n"
849 " configuration of the TPM\n"
850 "\n"
851 "--config <config file>\n"
852 " : Path to configuration file; default is %s\n"
853 "\n"
854 "--logfile <logfile>\n"
855 " : Path to log file; default is logging to stderr\n"
856 "\n"
857 "--keyfile <keyfile>\n"
858 " : Path to a key file containing the encryption key for the\n"
859 " TPM to encrypt its persistent state with. The content\n"
860 " must be a 32 hex digit number representing a 128bit AES key.\n"
861 " This parameter will be passed to the TPM using\n"
862 " '--key file=<file>'.\n"
863 "\n"
864 "--keyfile-fd <fd>: Like --keyfile but a file descriptor is given to read the\n"
865 " encryption key from.\n"
866 "\n"
867 "--pwdfile <pwdfile>\n"
868 " : Path to a file containing a passphrase from which the\n"
869 " TPM will derive the 128bit AES key. The passphrase can be\n"
870 " 32 bytes long.\n"
871 " This parameter will be passed to the TPM using\n"
872 " '--key pwdfile=<file>'.\n"
873 "\n"
874 "--pwdfile-fd <fd>: Like --pwdfile but a file descriptor is given to to read\n"
875 " the passphrase from.\n"
876 "\n"
877 "--cipher <cipher>: The cipher to use; either aes-128-cbc or aes-256-cbc;\n"
878 " the default is aes-128-cbc; the same cipher must be\n"
879 " used on the swtpm command line\n"
880 "\n"
881 "--overwrite : Overwrite existing TPM state by re-initializing it; if this\n"
882 " option is not given, this program will return an error if\n"
883 " existing state is detected\n"
884 "\n"
885 "--not-overwrite : Do not overwrite existing TPM state but silently end\n"
886 "\n"
887 "--pcr-banks <banks>\n"
888 " : Set of PCR banks to activate. Provide a comma separated list\n"
889 " like 'sha1,sha256'. '-' to skip and leave all banks active.\n"
890 " Default: %s\n"
891 "\n"
892 "--rsa-keysize <keysize>\n"
893 " : The RSA key size of the EK key; 3072 bits may be supported\n"
894 " if libtpms supports it.\n"
895 " Default: %u\n"
896 "\n"
78559edd
SB
897 "--write-ek-cert-files <directory>\n"
898 " : Write EK cert files into the given directory\n"
899 "\n"
c125e34b
SB
900 "--tcsd-system-ps-file <file>\n"
901 " : This option is deprecated and has no effect.\n"
902 "\n"
903 "--print-capabilities\n"
904 " : Print JSON formatted capabilites added after v0.1 and exit.\n"
905 "\n"
2b607237
SB
906 "--create-config-files [[overwrite][,root]]\n"
907 " : Create swtpm_setup and swtpm-localca config files for a\n"
908 " user account.\n"
909 " overwrite: overwrite any existing files\n"
910 " root: allow to create files under root's home directory\n"
a7254fab 911 " skip-if-exist: if any file exists exit without error\n"
2b607237 912 "\n"
c125e34b
SB
913 "--version : Display version and exit\n"
914 "\n"
634e6705 915 "--help,-h : Display this help screen\n\n",
c125e34b
SB
916 prgname,
917 DEFAULT_OWNER_PASSWORD,
918 DEFAULT_SRK_PASSWORD,
919 default_config_file,
920 DEFAULT_PCR_BANKS,
921 DEFAULT_RSA_KEYSIZE
922 );
923}
924
3eac2477
SB
925static int get_supported_tpm_versions(gchar **swtpm_prg_l, gboolean *swtpm_has_tpm12,
926 gboolean *swtpm_has_tpm2)
927{
928 gboolean success;
929 g_autofree gchar *standard_output = NULL;
930 int exit_status = 0;
931 g_autoptr(GError) error = NULL;
932 g_autofree gchar **argv = NULL;
933 gchar *my_argv[] = { "--print-capabilities", NULL };
7b7dcbb8 934 g_autofree gchar *logop = NULL;
3eac2477
SB
935
936 argv = concat_arrays(swtpm_prg_l, my_argv, FALSE);
7b7dcbb8
ET
937
938 if (gl_LOGFILE != NULL) {
939 logop = g_strdup_printf("file=%s", gl_LOGFILE);
940 argv = concat_arrays(argv, (gchar*[]){"--log", logop, NULL}, TRUE);
941 }
942
3eac2477
SB
943 success = g_spawn_sync(NULL, argv, NULL, G_SPAWN_STDERR_TO_DEV_NULL, NULL, NULL,
944 &standard_output, NULL, &exit_status, &error);
945 if (!success) {
946 logerr(gl_LOGFILE, "Could not start swtpm '%s': %s\n", swtpm_prg_l[0], error->message);
947 return 1;
948 }
949
950 *swtpm_has_tpm12 = g_strstr_len(standard_output, -1, "\"tpm-1.2\"") != NULL;
951 *swtpm_has_tpm2 = g_strstr_len(standard_output, -1, "\"tpm-2.0\"") != NULL;
952
953 return 0;
954}
955
c125e34b
SB
956/* Get the support RSA key sizes.
957 * This function returns an array of ints like the following
958 * - [ 1024, 2048, 3072 ]
959 * - [] (empty array, indicating only 2048 bit RSA keys are supported)
960 */
961static int get_rsa_keysizes(unsigned long flags, gchar **swtpm_prg_l,
962 unsigned int **keysizes, size_t *n_keysizes)
963{
964 gboolean success;
965 gchar *standard_output = NULL;
966 int exit_status = 0;
967 GError *error = NULL;
968 int ret = 1;
969 const gchar *needle = "\"rsa-keysize-";
970 unsigned int keysize;
971 gchar **argv = NULL;
972 char *p;
973 int n;
7b7dcbb8 974 g_autofree gchar *logop = NULL;
c125e34b
SB
975
976 *n_keysizes = 0;
977
978 if (flags & SETUP_TPM2_F) {
979 gchar *my_argv[] = { "--tpm2", "--print-capabilities", NULL };
980
981 argv = concat_arrays(swtpm_prg_l, my_argv, FALSE);
982
7b7dcbb8
ET
983 if (gl_LOGFILE != NULL) {
984 logop = g_strdup_printf("file=%s", gl_LOGFILE);
985 argv = concat_arrays(argv, (gchar*[]){"--log", logop, NULL}, TRUE);
986 }
987
c125e34b
SB
988 success = g_spawn_sync(NULL, argv, NULL, G_SPAWN_STDERR_TO_DEV_NULL, NULL, NULL,
989 &standard_output, NULL, &exit_status, &error);
990 if (!success) {
991 logerr(gl_LOGFILE, "Could not start swtpm '%s': %s\n", swtpm_prg_l[0], error->message);
a59eead4 992 g_error_free(error);
c125e34b
SB
993 goto error;
994 }
995
996 p = standard_output;
997 /* A crude way of parsing the json output just looking for "rsa-keysize-%u" */
998 while ((p = g_strstr_len(p, -1, needle)) != NULL) {
999 p += strlen(needle);
1000 n = sscanf(p, "%u\"", &keysize);
1001 if (n == 1) {
1002 *keysizes = g_realloc(*keysizes, (*n_keysizes + 1) * sizeof(unsigned int));
1003 (*keysizes)[*n_keysizes] = keysize;
1004 (*n_keysizes)++;
1005 }
1006 }
1007 }
1008 ret = 0;
1009
1010error:
1011 g_free(argv);
1012 g_free(standard_output);
1013
1014 return ret;
1015}
1016
1017/* Return the RSA key size capabilities in a NULL-terminated array */
1018static int get_rsa_keysize_caps(unsigned long flags, gchar **swtpm_prg_l,
1019 gchar ***keysize_strs)
1020{
1021 unsigned int *keysizes = NULL;
1022 size_t n_keysizes = 0;
1023 size_t i, j;
1024 int ret = get_rsa_keysizes(flags, swtpm_prg_l, &keysizes, &n_keysizes);
1025 if (ret)
1026 return ret;
1027
1028 *keysize_strs = g_malloc0(sizeof(char *) * (n_keysizes + 1));
1029 for (i = 0, j = 0; i < n_keysizes; i++) {
1030 if (keysizes[i] >= 2048)
1031 (*keysize_strs)[j++] = g_strdup_printf("tpm2-rsa-keysize-%u", keysizes[i]);
1032 }
1033
1034 g_free(keysizes);
1035
1036 return 0;
1037}
1038
1039/* Print teh JSON object of swtpm_setup's capabilities */
3eac2477
SB
1040static int print_capabilities(char **swtpm_prg_l, gboolean swtpm_has_tpm12,
1041 gboolean swtpm_has_tpm2)
c125e34b
SB
1042{
1043 g_autofree gchar *param = g_strdup("");
1044 gchar **keysize_strs = NULL;
1045 gchar *tmp;
1046 size_t i;
1047 int ret = 0;
1048
1049 ret = get_rsa_keysize_caps(SETUP_TPM2_F, swtpm_prg_l, &keysize_strs);
1050 if (ret)
1051 return 1;
1052
1053 for (i = 0; keysize_strs[i] != NULL; i++) {
1054 tmp = g_strdup_printf("%s, \"%s\"", param, keysize_strs[i]);
1055 g_free(param);
1056 param = tmp;
1057 }
1058
1059 printf("{ \"type\": \"swtpm_setup\", "
3eac2477 1060 "\"features\": [ %s%s\"cmdarg-keyfile-fd\", \"cmdarg-pwdfile-fd\", \"tpm12-not-need-root\""
2b607237 1061 ", \"cmdarg-write-ek-cert-files\", \"cmdarg-create-config-files\""
155ccdf5
MAL
1062 "%s ], "
1063 "\"version\": \"" VERSION "\" "
3eac2477
SB
1064 "}\n",
1065 swtpm_has_tpm12 ? "\"tpm-1.2\", " : "",
1066 swtpm_has_tpm2 ? "\"tpm-2.0\", " : "",
1067 param);
c125e34b
SB
1068
1069 g_strfreev(keysize_strs);
1070
1071 return 0;
1072}
1073
1074static int change_process_owner(const char *user)
1075{
1076 char *endptr;
1077 unsigned long long uid = strtoull(user, &endptr, 10);
1078 gid_t gid;
1079 struct passwd *passwd;
1080 int ret = 1;
1081
1082 if (*endptr != '\0') {
1083 /* assuming a name */
1084 passwd = getpwnam(user);
1085 if (passwd == NULL) {
1086 logerr(gl_LOGFILE, "Error: User '%s' does not exist.\n", user);
1087 goto error;
1088 }
1089
1090 if (initgroups(passwd->pw_name, passwd->pw_gid) != 0) {
1091 logerr(gl_LOGFILE, "Error: initgroups() failed: %s\n", strerror(errno));
1092 goto error;
1093 }
1094
1095 gid = passwd->pw_gid;
1096 uid = passwd->pw_uid;
1097 } else {
1098 if (uid > 0xffffffff) {
1099 logerr(gl_LOGFILE, "Error: uid %s outside valid range.\n", user);
1100 goto error;
1101 }
1102 gid = (gid_t)uid;
1103 }
1104
1105 if (setgid(gid) != 0) {
1106 logerr(gl_LOGFILE, "Error: setgid(%d) failed: %s\n", gid, strerror(errno));
1107 goto error;
1108 }
1109
1110 if (setuid(uid) != 0) {
1111 logerr(gl_LOGFILE, "Error: setuid(%d) failed: %s\n", uid, strerror(errno));
1112 goto error;
1113 }
1114
1115 ret = 0;
1116
1117error:
1118 return ret;
1119}
1120
2b607237
SB
1121static int handle_create_config_files(const char *optarg)
1122{
1123 g_auto(GStrv) tokens = NULL;
1124 gboolean overwrite = FALSE;
1125 gboolean root_flag = FALSE;
a7254fab 1126 gboolean skip_if_exist = FALSE;
2b607237
SB
1127
1128 if (optarg) {
1129 tokens = g_strsplit_set(optarg, ", ", -1);
1130 overwrite = g_strv_contains((const gchar **)tokens, "overwrite");
1131 root_flag = g_strv_contains((const gchar **)tokens, "root");
a7254fab
SB
1132 skip_if_exist = g_strv_contains((const gchar **)tokens, "skip-if-exist");
1133 if (overwrite && skip_if_exist) {
1134 fprintf(stderr, "Error: overwrite and skip-if-exist cannot both be used\n");
1135 return 1;
1136 }
2b607237
SB
1137 }
1138
a7254fab 1139 return create_config_files(overwrite, root_flag, skip_if_exist);
2b607237
SB
1140}
1141
c125e34b
SB
1142int main(int argc, char *argv[])
1143{
1144 int opt, option_index = 0;
a69388c0 1145 static const struct option long_options[] = {
c125e34b
SB
1146 {"tpm-state", required_argument, NULL, 't'},
1147 {"tpmstate", required_argument, NULL, 't'}, /* alias for tpm-state */
1148 {"tpm", required_argument, NULL, 'T'},
1149 {"swtpm_ioctl", required_argument, NULL, '_'},
1150 {"tpm2", no_argument, NULL, '2'},
1151 {"ecc", no_argument, NULL, 'e'},
1152 {"createek", no_argument, NULL, 'c'},
1153 {"create-spk", no_argument, NULL, 'C'},
1154 {"take-ownership", no_argument, NULL, 'o'},
1155 {"ownerpass", required_argument, NULL, 'O'},
1156 {"owner-well-known", no_argument, NULL, 'w'},
1157 {"srkpass", required_argument, NULL, 'S'},
1158 {"srk-well-known", no_argument, NULL, 's'},
1159 {"create-ek-cert", no_argument, NULL, 'E'},
1160 {"create-platform-cert", no_argument, NULL, 'P'},
1161 {"lock-nvram", no_argument, NULL, 'L'},
1162 {"display", no_argument, NULL, 'i'},
1163 {"config", required_argument, NULL, 'f'},
1164 {"vmid", required_argument, NULL, 'm'},
1165 {"keyfile", required_argument, NULL, 'x'},
1166 {"keyfile-fd", required_argument, NULL, 'X'},
1167 {"pwdfile", required_argument, NULL, 'k'},
1168 {"pwdfile-fd", required_argument, NULL, 'K'},
1169 {"cipher", required_argument, NULL, 'p'},
1170 {"runas", required_argument, NULL, 'r'},
1171 {"logfile", required_argument, NULL, 'l'},
1172 {"overwrite", no_argument, NULL, 'v'},
1173 {"not-overwrite", no_argument, NULL, 'V'},
1174 {"allow-signing", no_argument, NULL, 'a'},
1175 {"decryption", no_argument, NULL, 'd'},
1176 {"pcr-banks", required_argument, NULL, 'b'},
1177 {"rsa-keysize", required_argument, NULL, 'A'},
78559edd 1178 {"write-ek-cert-files", required_argument, NULL, '3'},
2b607237 1179 {"create-config-files", optional_argument, NULL, 'u'},
c125e34b
SB
1180 {"tcsd-system-ps-file", required_argument, NULL, 'F'},
1181 {"version", no_argument, NULL, '1'},
1182 {"print-capabilities", no_argument, NULL, 'y'},
1183 {"help", no_argument, NULL, 'h'},
1184 {NULL, 0, NULL, 0}
1185 };
1186 unsigned long flags = 0;
1187 g_autofree gchar *swtpm_prg = NULL;
1188 g_autofree gchar *tpm_state_path = NULL;
81371f66
SR
1189 struct swtpm_backend_ops *backend_ops = &swtpm_backend_dir;
1190 void *backend_state = NULL;
c125e34b
SB
1191 g_autofree gchar *config_file = NULL;
1192 g_autofree gchar *ownerpass = NULL;
1193 gboolean got_ownerpass = FALSE;
1194 g_autofree gchar *srkpass = NULL;
1195 gboolean got_srkpass = FALSE;
1196 g_autofree gchar *vmid = NULL;
1197 g_autofree gchar *pcr_banks = NULL;
1198 gboolean printcapabilities = FALSE;
1199 g_autofree gchar *keyfile = NULL;
1200 long int keyfile_fd = -1;
1201 g_autofree gchar *pwdfile = NULL;
1202 long int pwdfile_fd = -1;
1203 g_autofree gchar *cipher = g_strdup("aes-128-cbc");
1204 g_autofree gchar *rsa_keysize_str = g_strdup_printf("%d", DEFAULT_RSA_KEYSIZE);
1205 unsigned int rsa_keysize;
1206 g_autofree gchar *swtpm_keyopt = NULL;
1207 g_autofree gchar *runas = NULL;
20ca1eb3 1208 g_autofree gchar *certsdir = NULL;
78559edd 1209 g_autofree gchar *user_certsdir = NULL;
c125e34b
SB
1210 gchar *tmp;
1211 gchar **swtpm_prg_l = NULL;
1212 gchar **tmp_l = NULL;
1213 size_t i, n;
1214 struct stat statbuf;
1215 const struct passwd *curr_user;
1216 struct group *curr_grp;
1217 char *endptr;
8def57fa
SB
1218 gboolean swtpm_has_tpm12 = FALSE;
1219 gboolean swtpm_has_tpm2 = FALSE;
c125e34b
SB
1220 int fds_to_pass[1] = { -1 };
1221 unsigned n_fds_to_pass = 0;
1222 char tmpbuffer[200];
1223 time_t now;
1224 struct tm *tm;
1225 int ret = 1;
20ca1eb3 1226 g_autoptr(GError) error = NULL;
c125e34b
SB
1227
1228 if (init(&config_file) < 0)
1229 goto error;
1230
1231 swtpm_prg = g_find_program_in_path("swtpm");
1232 if (swtpm_prg) {
1233 tmp = g_strconcat(swtpm_prg, " socket", NULL);
1234 g_free(swtpm_prg);
1235 swtpm_prg = tmp;
1236 }
1237
1238 while ((opt = getopt_long(argc, argv, "h?",
1239 long_options, &option_index)) != -1) {
1240 switch (opt) {
1241 case 't': /* --tpmstate, --tpm-state */
1242 g_free(tpm_state_path);
81371f66
SR
1243 if (strncmp(optarg, "dir://", 6) == 0) {
1244 tpm_state_path = g_strdup(optarg);
6f8b8c62
SR
1245 } else if (strncmp(optarg, "file://", 7) == 0) {
1246 tpm_state_path = g_strdup(optarg);
1247 backend_ops = &swtpm_backend_file;
81371f66
SR
1248 } else {
1249 /* always prefix with dir:// so we can pass verbatim to swtpm */
1250 tpm_state_path = g_strconcat("dir://", optarg, NULL);
1251 }
c125e34b
SB
1252 break;
1253 case 'T': /* --tpm */
1254 g_free(swtpm_prg);
1255 swtpm_prg = g_strdup(optarg);
1256 break;
1257 case '_': /* --swtpm_ioctl */
1258 fprintf(stdout, "Warning: --swtpm_ioctl is deprecated and has no effect.");
1259 break;
1260 case '2': /* --tpm2 */
1261 flags |= SETUP_TPM2_F;
1262 break;
1263 case 'e': /* --ecc */
1264 flags |= SETUP_TPM2_ECC_F;
1265 break;
1266 case 'c': /* --createek */
1267 flags |= SETUP_CREATE_EK_F;
1268 break;
1269 case 'C': /* --create-spk */
1270 flags |= SETUP_CREATE_SPK_F;
1271 break;
1272 case 'o': /* --take-ownership */
1273 flags |= SETUP_CREATE_EK_F | SETUP_TAKEOWN_F;
1274 break;
1275 case 'O': /* --ownerpass */
1276 g_free(ownerpass);
1277 ownerpass = g_strdup(optarg);
1278 got_ownerpass = TRUE;
1279 break;
1280 case 'w': /* --owner-well-known */
1281 flags |= SETUP_OWNERPASS_ZEROS_F;
1282 got_ownerpass = TRUE;
1283 break;
1284 case 'S': /* --srk-pass */
1285 g_free(srkpass);
1286 srkpass = g_strdup(optarg);
1287 got_srkpass = TRUE;
1288 break;
1289 case 's': /* --srk-well-known */
1290 flags |= SETUP_SRKPASS_ZEROS_F;
1291 got_srkpass = TRUE;
1292 break;
1293 case 'E': /* --create-ek-cert */
1294 flags |= SETUP_CREATE_EK_F | SETUP_EK_CERT_F;
1295 break;
1296 case 'P': /* --create-platform-cert */
1297 flags |= SETUP_CREATE_EK_F | SETUP_PLATFORM_CERT_F;
1298 break;
1299 case 'L': /* --lock-nvram */
1300 flags |= SETUP_LOCK_NVRAM_F;
1301 break;
1302 case 'i': /* --display */
1303 flags |= SETUP_DISPLAY_RESULTS_F;
1304 break;
1305 case 'f': /* --config */
1306 g_free(config_file);
1307 config_file = g_strdup(optarg);
1308 break;
1309 case 'm': /* --vmid */
1310 g_free(vmid);
1311 vmid = g_strdup(optarg);
1312 break;
1313 case 'x': /* --keyfile */
1314 g_free(keyfile);
1315 keyfile = g_strdup(optarg);
1316 break;
1317 case 'X': /* --pwdfile-fd' */
1318 keyfile_fd = strtoull(optarg, &endptr, 10);
1319 if (*endptr != '\0' && keyfile_fd >= INT_MAX) {
1320 fprintf(stderr, "Invalid file descriptor '%s'\n", optarg);
1321 goto error;
1322 }
1323 break;
1324 case 'k': /* --pwdfile */
1325 g_free(pwdfile);
1326 pwdfile = g_strdup(optarg);
1327 break;
1328 case 'K': /* --pwdfile-fd' */
1329 pwdfile_fd = strtoull(optarg, &endptr, 10);
1330 if (*endptr != '\0' || pwdfile_fd >= INT_MAX) {
1331 fprintf(stderr, "Invalid file descriptor '%s'\n", optarg);
1332 goto error;
1333 }
1334 break;
1335 case 'p': /* --cipher */
1336 g_free(cipher);
1337 cipher = g_strdup(optarg);
1338 break;
1339 case 'r': /* --runas */
1340 g_free(runas);
1341 runas = g_strdup(optarg);
1342 break;
1343 case 'l': /* --logfile */
1344 g_free(gl_LOGFILE);
1345 gl_LOGFILE = g_strdup(optarg);
1346 break;
1347 case 'v': /* --overwrite */
1348 flags |= SETUP_STATE_OVERWRITE_F;
1349 break;
1350 case 'V': /* --not-overwrite */
1351 flags |= SETUP_STATE_NOT_OVERWRITE_F;
1352 break;
1353 case 'a': /* --allow-signing */
1354 flags |= SETUP_ALLOW_SIGNING_F;
1355 break;
1356 case 'd': /* --decryption */
1357 flags |= SETUP_DECRYPTION_F;
1358 break;
1359 case 'b': /* --pcr-banks */
1360 tmp = g_strconcat(pcr_banks ? pcr_banks: "",
1361 pcr_banks ? "," : "", g_strstrip(optarg), NULL);
1362 g_free(pcr_banks);
1363 pcr_banks = tmp;
1364 break;
1365 case 'A': /* --rsa-keysize */
1366 g_free(rsa_keysize_str);
1367 rsa_keysize_str = strdup(optarg);
1368 break;
78559edd
SB
1369 case '3': /* --write-ek-cert-files */
1370 g_free(user_certsdir);
1371 user_certsdir = g_strdup(optarg);
1372 flags |= SETUP_WRITE_EK_CERT_FILES_F;
1373 break;
2b607237
SB
1374 case 'u':
1375 if (optarg == NULL && optind < argc && argv[optind][0] != '0')
1376 optarg = argv[optind++];
1377 ret = handle_create_config_files(optarg);
1378 goto out;
c125e34b
SB
1379 case 'F': /* --tcsd-system-ps-file */
1380 printf("Warning: --tcsd-system-ps-file is deprecated and has no effect.");
1381 break;
1382 case '1': /* --version */
1383 versioninfo();
1384 ret = 0;
1385 goto error;
1386 case 'y': /* --print-capabilities */
1387 printcapabilities = TRUE;
1388 break;
1389 case '?':
1390 case 'h': /* --help */
1391 usage(argv[0], config_file);
634e6705
SB
1392 if (opt == 'h')
1393 ret = 0;
c125e34b
SB
1394 goto out;
1395 default:
1396 fprintf(stderr, "Unknown option code %d\n", opt);
1397 usage(argv[0], config_file);
1398 goto error;
1399 }
1400 }
1401
1402 if (swtpm_prg == NULL) {
1403 logerr(gl_LOGFILE,
1404 "Default TPM 'swtpm' could not be found and was not provided using --tpm\n.");
1405 goto error;
1406 }
1407
1408 swtpm_prg_l = split_cmdline(swtpm_prg);
1409 tmp = g_find_program_in_path(swtpm_prg_l[0]);
1410 if (!tmp) {
afef7050 1411 logerr(gl_LOGFILE, "swtpm at %s is not an executable.\n", swtpm_prg_l[0]);
c125e34b
SB
1412 goto error;
1413 }
1414 g_free(tmp);
1415
3eac2477
SB
1416
1417 ret = get_supported_tpm_versions(swtpm_prg_l, &swtpm_has_tpm12, &swtpm_has_tpm2);
1418 if (ret != 0)
1419 goto error;
1420
c125e34b 1421 if (printcapabilities) {
3eac2477 1422 ret = print_capabilities(swtpm_prg_l, swtpm_has_tpm12, swtpm_has_tpm2);
c125e34b
SB
1423 goto out;
1424 }
1425
3eac2477
SB
1426 if ((flags & SETUP_TPM2_F) != 0 && !swtpm_has_tpm2) {
1427 logerr(gl_LOGFILE, "swtpm at %s does not support TPM 2\n", swtpm_prg_l[0]);
1428 goto error;
1429 } else if ((flags & SETUP_TPM2_F) == 0 && !swtpm_has_tpm12){
1430 logerr(gl_LOGFILE, "swtpm at %s does not support TPM 1.2\n", swtpm_prg_l[0]);
1431 goto error;
1432 }
1433
c125e34b
SB
1434 if (runas) {
1435 ret = change_process_owner(runas);
1436 if (ret != 0)
1437 goto error;
1438 }
1439
1440 if (!got_ownerpass)
1441 ownerpass = g_strdup(DEFAULT_OWNER_PASSWORD);
1442 if (!got_srkpass)
1443 srkpass = g_strdup(DEFAULT_SRK_PASSWORD);
1444
c125e34b
SB
1445 if (gl_LOGFILE != NULL) {
1446 FILE *tmpfile;
1447 if (stat(gl_LOGFILE, &statbuf) == 0 &&
1448 (statbuf.st_mode & S_IFMT) == S_IFLNK) {
1449 fprintf(stderr, "Logfile must not be a symlink.\n");
1450 goto error;
1451 }
1452 tmpfile = fopen(gl_LOGFILE, "a");
1453 if (tmpfile == NULL) {
1454 fprintf(stderr, "Cannot write to logfile %s.\n", gl_LOGFILE);
1455 goto error;
1456 }
1457 fclose(tmpfile);
1458 }
1459
1460 curr_user = getpwuid(getuid());
1461
1462 // Check tpm_state_path directory and access rights
1463 if (tpm_state_path == NULL) {
1464 logerr(gl_LOGFILE, "--tpm-state must be provided\n");
1465 goto error;
1466 }
81371f66
SR
1467
1468 backend_state = backend_ops->parse_backend(tpm_state_path);
1469 if (!backend_state)
1470 goto error;
1471
1472 if (backend_ops->check_access(backend_state, R_OK|W_OK, curr_user) != 0)
c125e34b 1473 goto error;
c125e34b 1474
78559edd
SB
1475 if ((flags & SETUP_WRITE_EK_CERT_FILES_F)) {
1476 if (check_directory_access(user_certsdir, W_OK, curr_user) != 0)
1477 goto error;
1478 }
1479
c125e34b
SB
1480 if (flags & SETUP_TPM2_F) {
1481 if (flags & SETUP_TAKEOWN_F) {
1482 logerr(gl_LOGFILE, "Taking ownership is not supported for TPM 2.\n");
1483 goto error;
1484 }
1485 } else {
1486 if (flags & SETUP_TPM2_ECC_F) {
1487 logerr(gl_LOGFILE, "--ecc requires --tpm2.\n");
1488 goto error;
1489 }
1490 if (flags & SETUP_CREATE_SPK_F) {
1491 logerr(gl_LOGFILE, "--create-spk requires --tpm2.\n");
1492 goto error;
1493 }
1494 }
1495
e0d2c0ed 1496 ret = check_state_overwrite(swtpm_prg_l, flags, tpm_state_path);
c125e34b
SB
1497 if (ret == 1) {
1498 goto error;
1499 } else if (ret == 2) {
1500 ret = 0;
1501 goto out;
1502 }
1503
81371f66 1504 ret = backend_ops->delete_state(backend_state);
c125e34b
SB
1505 if (ret != 0)
1506 goto error;
1507
c125e34b
SB
1508 if (access(config_file, R_OK) != 0) {
1509 logerr(gl_LOGFILE, "User %s cannot read config file %s.\n",
1510 curr_user ? curr_user->pw_name : "<unknown>", config_file);
1511 goto error;
1512 }
1513
a5cc0bf6
SB
1514 /* check pcr_banks; read from config file if not given */
1515 tmp_l = g_strsplit(pcr_banks ? pcr_banks : "", ",", -1);
1516 for (i = 0, n = 0; tmp_l[i]; i++) {
1517 g_strstrip(tmp_l[i]);
1518 n += strlen(tmp_l[i]);
1519 }
1520 g_strfreev(tmp_l);
1521 if (n == 0) {
1522 g_free(pcr_banks);
1523 pcr_banks = get_default_pcr_banks(config_file);
1524 }
1525
c125e34b
SB
1526 if (cipher != NULL) {
1527 if (strcmp(cipher, "aes-128-cbc") != 0 &&
1528 strcmp(cipher, "aes-cbc") != 0 &&
1529 strcmp(cipher, "aes-256-cbc") != 0) {
1530 logerr(gl_LOGFILE, "Unsupported cipher %s.\n", cipher);
1531 goto error;
1532 }
1533 tmp = g_strdup_printf(",mode=%s", cipher);
1534 g_free(cipher);
1535 cipher = tmp;
1536 }
1537
1538 if (keyfile != NULL) {
1539 if (access(keyfile, R_OK) != 0) {
1540 logerr(gl_LOGFILE, "User %s cannot read keyfile %s.\n",
1541 curr_user ? curr_user->pw_name : "<unknown>", keyfile);
1542 goto error;
1543 }
1544 swtpm_keyopt = g_strdup_printf("file=%s%s", keyfile, cipher);
1545 logit(gl_LOGFILE, " The TPM's state will be encrypted with a provided key.\n");
1546 } else if (pwdfile != NULL) {
1547 if (access(pwdfile, R_OK) != 0) {
1548 logerr(gl_LOGFILE, "User %s cannot read passphrase file %s.\n",
1549 curr_user ? curr_user->pw_name : "<unknown>", pwdfile);
1550 goto error;
1551 }
1552 swtpm_keyopt = g_strdup_printf("pwdfile=%s%s", pwdfile, cipher);
1553 logit(gl_LOGFILE, " The TPM's state will be encrypted using a key derived from a passphrase.\n");
1554 } else if (keyfile_fd >= 0) {
1555 fds_to_pass[n_fds_to_pass++] = keyfile_fd;
1556 swtpm_keyopt = g_strdup_printf("fd=%ld%s", keyfile_fd, cipher);
1557 logit(gl_LOGFILE, " The TPM's state will be encrypted with a provided key (fd).\n");
1558 } else if (pwdfile_fd >= 0) {
1559 fds_to_pass[n_fds_to_pass++] = pwdfile_fd;
1560 swtpm_keyopt = g_strdup_printf("pwdfd=%ld%s", pwdfile_fd, cipher);
1561 logit(gl_LOGFILE, " The TPM's state will be encrypted using a key derived from a passphrase (fd).\n");
1562 }
1563
1564 if (strcmp(rsa_keysize_str, "max") == 0) {
1565 unsigned int *keysizes = NULL;
1566 size_t n_keysizes;
1567
1568 ret = get_rsa_keysizes(flags, swtpm_prg_l, &keysizes, &n_keysizes);
1569 if (ret)
1570 goto error;
1571 g_free(rsa_keysize_str);
1572 if (n_keysizes > 0) {
1573 /* last one is the biggest one */
1574 rsa_keysize_str = g_strdup_printf("%u", keysizes[n_keysizes - 1]);
1575 } else {
1576 rsa_keysize_str = g_strdup("2048");
1577 }
1578 g_free(keysizes);
1579 }
1580 if (strcmp(rsa_keysize_str, "2048") == 0 || strcmp(rsa_keysize_str, "3072") == 0) {
1581 unsigned int *keysizes = NULL;
1582 size_t n_keysizes;
1583 gboolean found = FALSE;
1584
1585 ret = get_rsa_keysizes(flags, swtpm_prg_l, &keysizes, &n_keysizes);
1586 if (ret)
1587 goto error;
1588
1589 rsa_keysize = strtoull(rsa_keysize_str, NULL, 10);
1590 for (i = 0; i < n_keysizes && found == FALSE; i++)
1591 found = (keysizes[i] == rsa_keysize);
1592 if (!found && rsa_keysize != 2048) {
1593 logerr(gl_LOGFILE, "%u bit RSA keys are not supported by libtpms.\n", rsa_keysize);
1594 goto error;
1595 }
1596 g_free(keysizes);
1597 } else {
1598 logit(gl_LOGFILE, "Unsupported RSA key size %s.\n", rsa_keysize_str);
1599 goto error;
1600 }
1601
1602 now = time(NULL);
1603 tm = localtime(&now);
1604 if (strftime(tmpbuffer, sizeof(tmpbuffer), "%a %d %h %Y %I:%M:%S %p %Z", tm) == 0) {
1605 logerr(gl_LOGFILE, "Could not format time/date string.\n");
1606 goto error;
1607 }
1608 curr_grp = getgrgid(getgid());
1609 logit(gl_LOGFILE, "Starting vTPM manufacturing as %s:%s @ %s\n",
1610 curr_user ? curr_user->pw_name : "<unknown>",
1611 curr_grp ? curr_grp->gr_name : "<unknown>",
1612 tmpbuffer);
1613
20ca1eb3
ET
1614 if (flags & (SETUP_EK_CERT_F | SETUP_PLATFORM_CERT_F)) {
1615 certsdir = g_dir_make_tmp("swtpm_setup.certs.XXXXXX", &error);
1616 if (certsdir == NULL) {
1617 logerr(gl_LOGFILE, "Could not create temporary directory for certs: %s\n",
1618 error->message);
1619 goto error;
1620 }
1621 }
1622
c125e34b
SB
1623 if ((flags & SETUP_TPM2_F) == 0) {
1624 ret = init_tpm(flags, swtpm_prg_l, config_file, tpm_state_path, ownerpass, srkpass, vmid,
20ca1eb3 1625 swtpm_keyopt, fds_to_pass, n_fds_to_pass, certsdir, user_certsdir);
c125e34b
SB
1626 } else {
1627 ret = init_tpm2(flags, swtpm_prg_l, config_file, tpm_state_path, vmid, pcr_banks,
20ca1eb3
ET
1628 swtpm_keyopt, fds_to_pass, n_fds_to_pass, rsa_keysize, certsdir,
1629 user_certsdir);
c125e34b
SB
1630 }
1631
1632 if (ret == 0) {
1633 logit(gl_LOGFILE, "Successfully authored TPM state.\n");
1634 } else {
1635 logerr(gl_LOGFILE, "An error occurred. Authoring the TPM state failed.\n");
81371f66 1636 backend_ops->delete_state(backend_state);
c125e34b
SB
1637 }
1638
1639 now = time(NULL);
1640 tm = localtime(&now);
1641 if (strftime(tmpbuffer, sizeof(tmpbuffer), "%a %d %h %Y %I:%M:%S %p %Z", tm) == 0) {
1642 logerr(gl_LOGFILE, "Could not format time/date string.\n");
1643 goto error;
1644 }
1645 logit(gl_LOGFILE, "Ending vTPM manufacturing @ %s\n",
1646 tmpbuffer);
1647
1648out:
20ca1eb3
ET
1649 if (certsdir && g_rmdir(certsdir) != 0)
1650 logerr(gl_LOGFILE, "Could not remove temporary directory for certs: %s\n",
1651 strerror(errno));
1652
81371f66
SR
1653 if (backend_ops && backend_state)
1654 backend_ops->free_backend(backend_state);
c125e34b
SB
1655 g_strfreev(swtpm_prg_l);
1656 g_free(gl_LOGFILE);
1657
b30a16ed 1658 return ret;
68ac6478
SB
1659
1660error:
1661 ret = 1;
1662 goto out;
c125e34b 1663}