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