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