• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

stefanberger / swtpm / #2885

24 Feb 2026 07:01PM UTC coverage: 71.687% (-0.7%) from 72.417%
#2885

push

travis-ci

web-flow
Merge 4834fc88d into 48358b244

34 of 215 new or added lines in 8 files covered. (15.81%)

466 existing lines in 9 files now uncovered.

7530 of 10504 relevant lines covered (71.69%)

10227.55 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

78.2
/src/swtpm_setup/swtpm_setup.c
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
#include <sys/wait.h>
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

33
#include <libtpms/tpm_nvfilename.h>
34

35
#include "profile.h"
36
#include "swtpm.h"
37
#include "swtpm_conf.h"
38
#include "swtpm_utils.h"
39
#include "swtpm_setup_utils.h"
40

41
#include <openssl/sha.h>
42

43
/* default values for passwords */
44
#define DEFAULT_OWNER_PASSWORD "ooo"
45
#define DEFAULT_SRK_PASSWORD   "sss"
46

47
#define SETUP_CREATE_EK_F           (1 << 0)
48
#define SETUP_TAKEOWN_F             (1 << 1)
49
#define SETUP_EK_CERT_F             (1 << 2)
50
#define SETUP_PLATFORM_CERT_F       (1 << 3)
51
#define SETUP_LOCK_NVRAM_F          (1 << 4)
52
#define SETUP_SRKPASS_ZEROS_F       (1 << 5)
53
#define SETUP_OWNERPASS_ZEROS_F     (1 << 6)
54
#define SETUP_STATE_OVERWRITE_F     (1 << 7)
55
#define SETUP_STATE_NOT_OVERWRITE_F (1 << 8)
56
#define SETUP_TPM2_F                (1 << 9)
57
#define SETUP_ALLOW_SIGNING_F       (1 << 10)
58
#define SETUP_TPM2_ECC_F            (1 << 11)
59
#define SETUP_CREATE_SPK_F          (1 << 12)
60
#define SETUP_DISPLAY_RESULTS_F     (1 << 13)
61
#define SETUP_DECRYPTION_F          (1 << 14)
62
#define SETUP_WRITE_EK_CERT_FILES_F (1 << 15)
63
#define SETUP_RECONFIGURE_F         (1 << 16)
64
#define SETUP_RSA_KEYSIZE_BY_USER_F (1 << 17)
65

66
/* default configuration file */
67
#define SWTPM_SETUP_CONF "swtpm_setup.conf"
68

69
/* Default logging goes to stderr */
70
gchar *gl_LOGFILE = NULL;
71

72
#define DEFAULT_RSA_KEYSIZE 2048
73

74

75
static const struct flag_to_certfile {
76
    unsigned long flag;
77
    const char *filename;
78
    const char *type;
79
} flags_to_certfiles[] = {
80
    {.flag = SETUP_EK_CERT_F      , .filename = "ek.cert",       .type = "ek" },
81
    {.flag = SETUP_PLATFORM_CERT_F, .filename = "platform.cert", .type = "platform" },
82
    {.flag = 0,                     .filename = NULL,            .type = NULL},
83
};
84

85
/* initialize the path of the config_file */
86
static int init(gchar **config_file)
182✔
87
{
88
    const gchar *configdir = g_get_user_config_dir();
182✔
89

90
    *config_file = g_build_filename(configdir, SWTPM_SETUP_CONF, NULL);
182✔
91
    if (access(*config_file, R_OK) != 0) {
182✔
92
        g_free(*config_file);
182✔
93
        *config_file = g_build_filename(SYSCONFDIR, SWTPM_SETUP_CONF, NULL);
182✔
94
    }
95

96
    return 0;
182✔
97
}
98

99
/* Get the spec and attributes parameters from swtpm */
100
static int tpm_get_specs_and_attributes(struct swtpm *swtpm, gchar ***params)
86✔
101
{
102
    int ret;
86✔
103
    g_autofree gchar *json = NULL;
172✔
104
    JsonParser *jp = NULL;
86✔
105
    GError *error = NULL;
86✔
106
    JsonReader *jr = NULL;
86✔
107
    JsonNode *root;
86✔
108
    static const struct parse_rule {
86✔
109
         const char *node1;
110
         const char *node2;
111
         gboolean is_int;
112
         const char *optname;
113
    } parser_rules[7] = {
114
         {"TPMSpecification", "family", FALSE, "--tpm-spec-family"},
115
         {"TPMSpecification", "level", TRUE, "--tpm-spec-level"},
116
         {"TPMSpecification", "revision", TRUE, "--tpm-spec-revision"},
117
         {"TPMAttributes", "manufacturer", FALSE, "--tpm-manufacturer"},
118
         {"TPMAttributes", "model", FALSE, "--tpm-model"},
119
         {"TPMAttributes", "version", FALSE, "--tpm-version"},
120
         {NULL, NULL, FALSE, NULL},
121
    };
122
    size_t idx;
86✔
123

124
    ret = swtpm->cops->ctrl_get_tpm_specs_and_attrs(swtpm, &json);
86✔
125
    if (ret != 0) {
86✔
126
        logerr(gl_LOGFILE, "Could not get the TPM spec and attribute parameters.\n");
×
127
        return 1;
×
128
    }
129

130
    jp = json_parser_new();
86✔
131

132
    if (!json_parser_load_from_data(jp, json, -1, &error)) {
86✔
133
        logerr(gl_LOGFILE, "JSON parser failed: %s\n", error->message);
×
134
        g_error_free(error);
×
135
        goto error;
×
136
    }
137

138
    *params = NULL;
86✔
139
    root = json_parser_get_root(jp);
86✔
140

141
    for (idx = 0; parser_rules[idx].node1 != NULL; idx++) {
688✔
142
        jr = json_reader_new(root);
516✔
143
        if (json_reader_read_member(jr, parser_rules[idx].node1) &&
1,032✔
144
            json_reader_read_member(jr, parser_rules[idx].node2)) {
516✔
145
            gchar *str;
516✔
146

147
            if (parser_rules[idx].is_int)
516✔
148
                str = g_strdup_printf("%ld", (long)json_reader_get_int_value(jr));
172✔
149
            else
150
                str = g_strdup(json_reader_get_string_value(jr));
344✔
151

152
            *params = concat_varrays(*params,
1,548✔
153
                                    (gchar*[]){
516✔
154
                                        g_strdup(parser_rules[idx].optname),
516✔
155
                                        str,
156
                                        NULL
157
                                    }, TRUE);
158
        } else {
159
            logerr(gl_LOGFILE, "Could not find [%s][%s] in '%s'\n",
×
160
                   parser_rules[idx].node1, parser_rules[idx].node2, json);
×
161
            ret = 1;
×
162
            break;
×
163
        }
164
        g_object_unref(jr);
516✔
165
        jr = NULL;
516✔
166
    }
167

168
    if (ret) {
×
169
        g_strfreev(*params);
×
170
        *params = NULL;
×
171
        g_object_unref(jr);
×
172
    }
173
error:
86✔
174
    g_object_unref(jp);
86✔
175

176
    return ret;
86✔
177
}
178

179
/* Call an external tool to create the certificates */
180
static int call_create_certs(unsigned long flags, unsigned int cert_flags,
86✔
181
                             const gchar *configfile, const gchar *certsdir,
182
                             const gchar *ekparam, const gchar *vmid, struct swtpm *swtpm)
183
{
184
    gchar **config_file_lines = NULL; /* must free */
86✔
185
    g_autofree gchar *create_certs_tool = NULL;
172✔
186
    g_autofree gchar *create_certs_tool_config = NULL;
86✔
187
    g_autofree gchar *create_certs_tool_options = NULL;
86✔
188
    g_autofree const gchar **cmd = NULL;
86✔
189
    gchar **params = NULL; /* must free */
86✔
190
    g_autofree gchar *prgname = NULL;
86✔
191
    gboolean success;
86✔
192
    gint exit_status;
86✔
193
    size_t idx, j;
86✔
194
    gchar *s;
86✔
195
    int ret;
86✔
196

197
    ret = tpm_get_specs_and_attributes(swtpm, &params);
86✔
198
    if (ret != 0)
86✔
199
        goto error;
×
200

201
    ret = read_file_lines(configfile, &config_file_lines);
86✔
202
    if (ret != 0)
86✔
203
        goto error;
×
204

205
    create_certs_tool = get_config_value(config_file_lines, "create_certs_tool");
86✔
206
    create_certs_tool_config = get_config_value(config_file_lines, "create_certs_tool_config");
86✔
207
    create_certs_tool_options = get_config_value(config_file_lines, "create_certs_tool_options");
86✔
208

209
    ret = 0;
86✔
210

211
    if (create_certs_tool != NULL) {
86✔
212
        g_autofree gchar *create_certs_tool_path = g_find_program_in_path(create_certs_tool);
172✔
213
        if (create_certs_tool_path == NULL) {
86✔
214
            logerr(gl_LOGFILE, "Could not find %s in PATH.\n", create_certs_tool);
×
215
            ret = 1;
×
216
            goto error;
×
217
        }
218

219
        if (flags & SETUP_TPM2_F) {
86✔
220
            params = concat_varrays(params,
78✔
221
                                (gchar*[]){
78✔
222
                                    g_strdup("--tpm2"),
78✔
223
                                    NULL
224
                                }, TRUE);
225
        }
226
        cmd = concat_arrays((const gchar*[]) {
86✔
227
                                create_certs_tool_path,
228
                                "--type", "_",  /* '_' must be at index '2' ! */
229
                                "--ek", ekparam,
230
                                "--dir", certsdir,
231
                                NULL
232
                            }, NULL, FALSE);
233

234
        if (flags & SETUP_ALLOW_SIGNING_F) {
86✔
235
            cmd = concat_arrays(cmd, (const gchar*[]){"--allow-signing", NULL}, TRUE);
42✔
236
            /* once --allow-signing is passed we need to pass --decryption also */
237
            if (flags & SETUP_DECRYPTION_F)
42✔
238
                cmd = concat_arrays(cmd, (const gchar*[]){"--decryption", NULL}, TRUE);
14✔
239
        }
240
        if (gl_LOGFILE != NULL)
86✔
241
            cmd = concat_arrays(cmd, (const gchar*[]){"--logfile", gl_LOGFILE, NULL}, TRUE);
11✔
242
        if (vmid != NULL)
86✔
243
            cmd = concat_arrays(cmd, (const gchar*[]){"--vmid", vmid, NULL}, TRUE);
75✔
244
        cmd = concat_arrays(cmd, (const char **)params, TRUE);
86✔
245
        if (create_certs_tool_config != NULL)
86✔
246
            cmd = concat_arrays(cmd, (const gchar*[]){"--configfile", create_certs_tool_config, NULL}, TRUE);
11✔
247
        if (create_certs_tool_options != NULL)
86✔
248
            cmd = concat_arrays(cmd, (const gchar*[]){"--optsfile", create_certs_tool_options, NULL}, TRUE);
11✔
249

250
        s = g_strrstr(create_certs_tool, G_DIR_SEPARATOR_S);
86✔
251
        if (s)
86✔
252
            prgname = strdup(&s[1]);
11✔
253
        else
254
            prgname = strdup(create_certs_tool);
75✔
255

256
        for (idx = 0; flags_to_certfiles[idx].filename != NULL; idx++) {
258✔
257
            if (cert_flags & flags_to_certfiles[idx].flag) {
172✔
258
                g_autofree gchar *standard_output = NULL;
132✔
259
                g_autofree gchar *standard_error = NULL;
132✔
260
                GError *error = NULL;
132✔
261
                gchar **lines;
132✔
262

263
                cmd[2] = (gchar *)flags_to_certfiles[idx].type; /* replaces the "_" above */
132✔
264

265
                s = g_strjoinv(" ", (char **)cmd);
132✔
266
                logit(gl_LOGFILE, "  Invoking %s\n", s);
132✔
267
                g_free(s);
132✔
268

269
                success = spawn_sync(NULL, cmd, NULL, 0, NULL, NULL,
132✔
270
                                     &standard_output, &standard_error, &exit_status, &error);
271
                if (!success) {
132✔
272
                    logerr(gl_LOGFILE, "An error occurred running %s: %s\n",
×
273
                           create_certs_tool, error->message);
×
274
                    g_error_free(error);
×
275
                    ret = 1;
×
276
                    break;
×
277
                } else if (exit_status != 0) {
132✔
278
                    logerr(gl_LOGFILE, "%s exit with status %d: %s\n",
×
279
                           prgname, WEXITSTATUS(exit_status), standard_error);
×
280
                    ret = 1;
×
281
                    break;
×
282
                }
283

284
                lines = g_strsplit(standard_output, "\n", -1);
132✔
285
                for (j = 0; lines[j] != NULL; j++) {
264✔
286
                    if (strlen(lines[j]) > 0)
×
287
                        logit(gl_LOGFILE, "%s: %s\n", prgname, lines[j]);
×
288
                }
289
                g_strfreev(lines);
132✔
290

291
                SWTPM_G_FREE(standard_output);
132✔
292
                SWTPM_G_FREE(standard_error);
132✔
293
            }
294
        }
295
    }
296

297
error:
×
298
    g_strfreev(config_file_lines);
86✔
299
    g_strfreev(params);
86✔
300

301
    return ret;
86✔
302
}
303

304
static char *create_certfile_name(const gchar *user_certsdir,
11✔
305
                                  const gchar *key_type,
306
                                  const gchar *key_description)
307
{
308
    g_autofree gchar *filename = g_strdup_printf("%s-%s.crt", key_type, key_description);
11✔
309

310
    return g_strjoin(G_DIR_SEPARATOR_S, user_certsdir, filename, NULL);
11✔
311
}
312

313
/*
314
 * Remove the cert file unless the user wants a copy of it.
315
 */
316
static int certfile_move_or_delete(unsigned long flags, gboolean preserve, const gchar *certfile,
132✔
317
                                   const gchar *user_certsdir, const gchar *key_type,
318
                                   const gchar *key_description)
319
{
320
    g_autofree gchar *content = NULL;
264✔
321
    g_autofree gchar *cf = NULL;
132✔
322
    gsize content_length;
132✔
323
    GError *error = NULL;
132✔
324
    size_t offset = 0;
132✔
325

326
    if (preserve && (flags & SETUP_WRITE_EK_CERT_FILES_F) && user_certsdir != NULL) {
132✔
327
        if (!g_file_get_contents(certfile, &content, &content_length, &error))
11✔
328
            goto error;
×
329

330
        cf = create_certfile_name(user_certsdir, key_type, key_description);
11✔
331
        if (!(flags & SETUP_TPM2_F)) {
11✔
332
            /* A TPM 1.2 certificate has a 7 byte header at the beginning
333
             * that we now remove */
334
            if (content_length >= 8)
1✔
335
                offset = 7;
1✔
336
        }
337
        if (!g_file_set_contents(cf, &content[offset], content_length - offset,
11✔
338
                                 &error))
339
            goto error;
×
340
        if (g_chmod(cf, S_IRUSR | S_IWUSR | S_IRGRP) < 0) {
11✔
341
            logerr(gl_LOGFILE, "Failed to chmod file '%s': %s\n", cf, strerror(errno));
×
342
            goto error_unlink;
×
343
        }
344
    }
345
    unlink(certfile);
132✔
346

347
    return 0;
132✔
348

349
error:
×
350
    logerr(gl_LOGFILE, "%s\n", error->message);
×
351
    g_error_free(error);
×
352

353
error_unlink:
×
354
    unlink(certfile);
×
355

356
    return 1;
×
357
}
358

359
static int read_certificate_file(const gchar *certsdir, const gchar *filename,
132✔
360
                                 gchar **filecontent, size_t *filecontent_len,
361
                                 gchar **certfile)
362
{
363
    *certfile = g_strjoin(G_DIR_SEPARATOR_S, certsdir, filename, NULL);
132✔
364

365
    return read_file(*certfile, filecontent, filecontent_len);
132✔
366
}
367

368
/*
369
 * Read the certificate from the file where swtpm_cert left it.
370
 * Write the file into the TPM's NVRAM and, if the user wants it,
371
 * copy it into a user-provided directory.
372
 */
373
static int tpm2_persist_certificate(unsigned long flags, const gchar *certsdir,
117✔
374
                                    const struct flag_to_certfile *ftc,
375
                                    unsigned int rsa_keysize, struct swtpm2 *swtpm2,
376
                                    const gchar *user_certsdir, const gchar *key_type,
377
                                    const gchar *key_description)
378
{
379
    g_autofree gchar *filecontent = NULL;
234✔
380
    g_autofree gchar *certfile = NULL;
117✔
381
    size_t filecontent_len;
117✔
382
    int ret;
117✔
383

384
    ret = read_certificate_file(certsdir, ftc->filename,
117✔
385
                                &filecontent, &filecontent_len, &certfile);
386
    if (ret != 0)
117✔
387
        goto error_unlink;
×
388

389
    if (ftc->flag == SETUP_EK_CERT_F) {
117✔
390
        ret = swtpm2->ops->write_ek_cert_nvram(&swtpm2->swtpm,
78✔
391
                                     !!(flags & SETUP_TPM2_ECC_F), rsa_keysize,
78✔
392
                                     !!(flags & SETUP_LOCK_NVRAM_F),
78✔
393
                                     (const unsigned char*)filecontent, filecontent_len);
394
    } else {
395
        ret = swtpm2->ops->write_platform_cert_nvram(&swtpm2->swtpm,
39✔
396
                                     !!(flags & SETUP_LOCK_NVRAM_F),
39✔
397
                                     (const unsigned char *)filecontent, filecontent_len);
398
    }
399

400
    if (ret != 0)
117✔
401
        goto error_unlink;
×
402

403
    return certfile_move_or_delete(flags, !!(ftc->flag & SETUP_EK_CERT_F),
117✔
404
                                   certfile, user_certsdir,
405
                                   key_type, key_description);
406

407
error_unlink:
×
408
    unlink(certfile);
×
409
    return 1;
×
410
}
411

412
/* Create EK and certificate for a TPM 2 */
413
static int tpm2_create_ek_and_cert(unsigned long flags, const gchar *config_file,
224✔
414
                                   const gchar *certsdir, const gchar *vmid,
415
                                   unsigned int rsa_keysize, struct swtpm2 *swtpm2,
416
                                   const gchar *user_certsdir)
417
{
418
    const char *key_description = "";
224✔
419
    g_autofree gchar *ekparam = NULL;
448✔
420
    unsigned long cert_flags;
224✔
421
    const gchar *key_type;
224✔
422
    size_t idx;
224✔
423
    int ret;
224✔
424

425
    if (flags & SETUP_CREATE_EK_F) {
224✔
426
        ret = swtpm2->ops->create_ek(&swtpm2->swtpm, !!(flags & SETUP_TPM2_ECC_F), rsa_keysize,
184✔
427
                                     !!(flags & SETUP_ALLOW_SIGNING_F),
92✔
428
                                     !!(flags & SETUP_DECRYPTION_F),
92✔
429
                                     !!(flags & SETUP_LOCK_NVRAM_F),
92✔
430
                                     &ekparam, &key_description);
431
        if (ret != 0)
92✔
432
            return 1;
433
    }
434

435
    /* Only look at ek and platform certs here */
436
    cert_flags = flags & (SETUP_EK_CERT_F | SETUP_PLATFORM_CERT_F);
224✔
437
    if (cert_flags) {
224✔
438
        ret = call_create_certs(flags, cert_flags, config_file, certsdir, ekparam,
78✔
439
                                vmid, &swtpm2->swtpm);
440
        if (ret != 0)
78✔
441
            return 1;
442

443
        for (idx = 0; flags_to_certfiles[idx].filename; idx++) {
234✔
444
            if (cert_flags & flags_to_certfiles[idx].flag) {
156✔
445
                key_type = flags_to_certfiles[idx].flag & SETUP_EK_CERT_F ? "ek" : "";
117✔
446

447
                ret = tpm2_persist_certificate(flags, certsdir, &flags_to_certfiles[idx],
117✔
448
                                               rsa_keysize, swtpm2, user_certsdir,
449
                                               key_type, key_description);
450
                if (ret)
117✔
451
                    return 1;
452
            }
453
        }
454
    }
455

456
    return 0;
457
}
458

459
/* Create endorsement keys and certificates for a TPM 2 */
460
static int tpm2_create_eks_and_certs(unsigned long flags, const gchar *config_file,
112✔
461
                                     const gchar *certsdir, const gchar *vmid,
462
                                     unsigned int rsa_keysize, struct swtpm2 *swtpm2,
463
                                     const gchar *user_certsdir)
464
{
465
     int ret;
112✔
466

467
     /* 1st key will be RSA */
468
     flags = flags & ~SETUP_TPM2_ECC_F;
112✔
469
     ret = tpm2_create_ek_and_cert(flags, config_file, certsdir, vmid, rsa_keysize, swtpm2,
112✔
470
                                   user_certsdir);
471
     if (ret != 0)
112✔
472
         return 1;
473

474
     /* 2nd key will be an ECC; no more platform cert */
475
     flags = (flags & ~SETUP_PLATFORM_CERT_F) | SETUP_TPM2_ECC_F;
112✔
476
     return tpm2_create_ek_and_cert(flags, config_file, certsdir, vmid, rsa_keysize, swtpm2,
112✔
477
                                    user_certsdir);
478
}
479

480
/* Get the default PCR banks from the config file and if nothing can
481
   be found there use the DEFAULT_PCR_BANKS #define.
482
 */
483
static gchar *get_default_pcr_banks(gchar *const *config_file_lines)
144✔
484
{
485
    gchar *pcr_banks;
144✔
486

487
    pcr_banks = get_config_value(config_file_lines, "active_pcr_banks");
144✔
488
    if (pcr_banks)
144✔
489
        g_strstrip(pcr_banks);
27✔
490
    if (pcr_banks == NULL || strlen(pcr_banks) == 0) {
144✔
491
        g_free(pcr_banks);
117✔
492
        pcr_banks = g_strdup(DEFAULT_PCR_BANKS);
117✔
493
    }
494
    return pcr_banks;
144✔
495
}
496

497
/* Get the default RSA keysize from the config file */
498
static gchar *get_default_rsa_keysize(gchar *const *config_file_lines)
131✔
499
{
500
    gchar *rsa_keysize;
131✔
501

502
    rsa_keysize = get_config_value(config_file_lines, "rsa_keysize");
131✔
503
    if (rsa_keysize)
131✔
504
        g_strstrip(rsa_keysize);
24✔
505
    if (rsa_keysize == NULL || strlen(rsa_keysize) == 0) {
131✔
506
        g_free(rsa_keysize);
107✔
507
        rsa_keysize = g_strdup_printf("%d", DEFAULT_RSA_KEYSIZE);
107✔
508
    }
509
    return rsa_keysize;
131✔
510
}
511

512
/* Get the default profile from the config file */
513
static gchar *get_default_profile(gchar *const *config_file_lines)
43✔
514
{
515
    gchar *profile;
43✔
516

517
    profile = get_config_value(config_file_lines, "profile");
43✔
518
    if (profile)
43✔
519
        g_strstrip(profile);
13✔
520
    return profile;
43✔
521
}
522

523
/* If available, open the default profile and return its file descriptor */
524
static int get_default_profile_fd(gchar *const *config_file_lines)
43✔
525
{
526
    g_autofree gchar *profile_file = NULL;
86✔
527
    int fd;
43✔
528

529
    profile_file = get_config_value(config_file_lines, "profile_file");
43✔
530
    if (!profile_file)
43✔
531
        return -1;
532

533
    fd = open(profile_file, O_RDONLY);
×
534
    if (fd < 0) {
×
535
        logerr(gl_LOGFILE, "Could not read default profile '%s': %s",
×
536
               profile_file, strerror(errno));
×
537
        return -2;
×
538
    }
539
    return fd;
540
}
541

542
/* Activate the given list of PCR banks. If pcr_banks is '-' then leave
543
 * the configuration as-is.
544
 */
545
static int tpm2_activate_pcr_banks(struct swtpm2 *swtpm2,
118✔
546
                                   const gchar *pcr_banks)
547
{
548
    g_autofree gchar *active_pcr_banks_join = NULL;
236✔
549
    g_autofree gchar *all_pcr_banks_join = NULL;
118✔
550
    g_auto(GStrv) active_pcr_banks = NULL;
118✔
551
    g_auto(GStrv) all_pcr_banks = NULL;
118✔
552
    g_auto(GStrv) pcr_banks_l = NULL;
118✔
553
    struct swtpm *swtpm = &swtpm2->swtpm;
118✔
554
    int ret = 0;
118✔
555

556
    if (g_str_equal(pcr_banks, "-"))
118✔
557
        return 0;
558

559
    ret = swtpm2->ops->get_all_pcr_banks(swtpm, &all_pcr_banks);
118✔
560
    if (ret != 0)
118✔
561
        return ret;
562

563
    pcr_banks_l = g_strsplit(pcr_banks, ",", -1);
118✔
564
    ret = swtpm2->ops->set_active_pcr_banks(swtpm, pcr_banks_l, all_pcr_banks,
118✔
565
                                            &active_pcr_banks);
566
    if (ret != 0)
118✔
567
        return ret;
568

569
    active_pcr_banks_join = g_strjoinv(",", active_pcr_banks);
117✔
570
    all_pcr_banks_join = g_strjoinv(",", all_pcr_banks);
117✔
571
    logit(gl_LOGFILE, "Successfully activated PCR banks %s among %s.\n",
117✔
572
          active_pcr_banks_join, all_pcr_banks_join);
573

574
    return 0;
117✔
575
}
576

577
static int log_active_profile(struct swtpm2 *swtpm2)
119✔
578
{
579
    g_autofree gchar *profile = NULL;
238✔
580
    char *tmp;
119✔
581

582
    profile = swtpm2->ops->get_active_profile(&swtpm2->swtpm);
119✔
583
    if (!profile) {
119✔
584
        logerr(gl_LOGFILE, "Could not get active profile.\n");
7✔
585
        return 1;
7✔
586
    }
587
    /* Strip out surrounding '{"ActiveProfile":<to display>} */
588
    tmp = strrchr(profile, '}');
112✔
589
    if (!tmp)
112✔
590
        goto malformatted;
×
591
    *tmp = 0;
112✔
592

593
    tmp = strchr(profile, ':');
112✔
594
    if (!tmp)
112✔
595
        goto malformatted;
×
596

597
    logit(gl_LOGFILE, "Active profile: %s\n", tmp + 1);
112✔
598
    return 0;
112✔
599

600
malformatted:
×
601
    logerr(gl_LOGFILE, "Malformatted active profile");
×
602
    return 1;
×
603
}
604

605
/* Simulate manufacturing a TPM 2: create keys and certificates */
606
static int init_tpm2(unsigned long flags, gchar **swtpm_prg_l, const gchar *config_file,
125✔
607
                     const gchar *tpm2_state_path, const gchar *vmid, const gchar *pcr_banks,
608
                     const gchar *swtpm_keyopt, int *fds_to_pass, size_t n_fds_to_pass,
609
                     unsigned int rsa_keysize, const gchar *certsdir,
610
                     const gchar *user_certsdir, const gchar *json_profile,
611
                     int json_profile_fd, const gchar *profile_remove_disabled_param)
612
{
613
    struct swtpm2 *swtpm2;
125✔
614
    struct swtpm *swtpm;
125✔
615
    int ret;
125✔
616

617
    swtpm2 = swtpm2_new(swtpm_prg_l, tpm2_state_path, swtpm_keyopt, gl_LOGFILE,
125✔
618
                        fds_to_pass, n_fds_to_pass, json_profile, json_profile_fd,
619
                        profile_remove_disabled_param);
620
    if (swtpm2 == NULL)
125✔
621
        return 1;
622
    swtpm = &swtpm2->swtpm;
125✔
623

624
    ret = swtpm->cops->start(swtpm);
125✔
625
    if (ret != 0) {
125✔
UNCOV
626
        logerr(gl_LOGFILE, "Could not start the TPM 2.\n");
×
UNCOV
627
        goto error;
×
628
    }
629

630
    if (!(flags & SETUP_RECONFIGURE_F)) {
125✔
631
        ret = log_active_profile(swtpm2);
119✔
632
        if (ret)
119✔
633
            goto error;
7✔
634

635
        if ((flags & SETUP_CREATE_SPK_F)) {
112✔
636
            ret = swtpm2->ops->create_spk(swtpm, !!(flags & SETUP_TPM2_ECC_F), rsa_keysize);
4✔
637
            if (ret != 0)
4✔
638
                goto destroy;
×
639
        }
640

641
        ret = tpm2_create_eks_and_certs(flags, config_file, certsdir, vmid, rsa_keysize, swtpm2,
112✔
642
                                        user_certsdir);
643
        if (ret != 0)
112✔
644
            goto destroy;
×
645
    }
646

647
    ret = tpm2_activate_pcr_banks(swtpm2, pcr_banks);
118✔
648
    if (ret != 0)
118✔
649
        goto destroy;
1✔
650

651
    ret = swtpm2->ops->shutdown(swtpm);
117✔
652

653
destroy:
118✔
654
    swtpm->cops->destroy(swtpm);
118✔
655

656
error:
125✔
657
    swtpm_free(swtpm);
125✔
658

659
    return ret;
125✔
660
}
661

662
/* Create the owner password digest */
663
static void tpm12_get_ownerpass_digest(unsigned long flags, const gchar *ownerpass,
9✔
664
                                       unsigned char ownerpass_digest[SHA_DIGEST_LENGTH])
665
{
666
    const gchar zeros[SHA_DIGEST_LENGTH]= {0, };
9✔
667
    size_t len;
9✔
668

669
    if (ownerpass == NULL) {
9✔
670
        if (flags & SETUP_OWNERPASS_ZEROS_F) {
2✔
671
            ownerpass = zeros;
672
            len = sizeof(zeros);
673
        } else {
674
            ownerpass = DEFAULT_OWNER_PASSWORD;
×
675
            len = strlen(ownerpass);
×
676
        }
677
    } else {
678
        len = strlen(ownerpass);
7✔
679
    }
680
    SHA1((const unsigned char *)ownerpass, len, ownerpass_digest);
9✔
681
}
9✔
682

683
/* Create the SRK password digest */
684
static void tpm12_get_srkpass_digest(unsigned long flags, const gchar *srkpass,
9✔
685
                                     unsigned char srkpass_digest[SHA_DIGEST_LENGTH])
686
{
687
    const gchar zeros[SHA_DIGEST_LENGTH]= {0, };
9✔
688
    size_t len;
9✔
689

690
    if (srkpass == NULL) {
9✔
691
        if (flags & SETUP_SRKPASS_ZEROS_F) {
2✔
692
            srkpass = zeros;
693
            len = sizeof(zeros);
694
        } else {
695
            srkpass = DEFAULT_SRK_PASSWORD;
×
696
            len = strlen(srkpass);
×
697
        }
698
    } else {
699
        len = strlen(srkpass);
7✔
700
    }
701
    SHA1((const unsigned char *)srkpass, len, srkpass_digest);
9✔
702
}
9✔
703

704
/* Take ownership of a TPM 1.2 */
705
static int tpm12_take_ownership(unsigned long flags, const gchar *ownerpass,
9✔
706
                                const gchar *srkpass, gchar *pubek, size_t pubek_len,
707
                                struct swtpm12 *swtpm12)
708
{
709
    unsigned char ownerpass_digest[SHA_DIGEST_LENGTH];
9✔
710
    unsigned char srkpass_digest[SHA_DIGEST_LENGTH];
9✔
711

712
    tpm12_get_ownerpass_digest(flags, ownerpass, ownerpass_digest);
9✔
713
    tpm12_get_srkpass_digest(flags, srkpass, srkpass_digest);
9✔
714

715
    return swtpm12->ops->take_ownership(&swtpm12->swtpm, ownerpass_digest, srkpass_digest,
9✔
716
                                        (const unsigned char *)pubek, pubek_len);
717
}
718

719
/* Create the certificates for a TPM 1.2 */
720
static int tpm12_create_certs(unsigned long flags, const gchar *config_file,
8✔
721
                              const gchar *certsdir, const gchar *ekparam,
722
                              const gchar *vmid, struct swtpm12 *swtpm12,
723
                              const gchar *user_certsdir)
724
{
725
    g_autofree gchar *filecontent = NULL;
16✔
726
    g_autofree gchar *certfile = NULL;
8✔
727
    unsigned int cert_flags;
8✔
728
    const gchar *key_type;
8✔
729
    gsize filecontent_len;
8✔
730
    size_t idx;
8✔
731
    int ret;
8✔
732

733
    /* TPM 1.2 only has ek and platform certs */
734
    cert_flags = flags & (SETUP_EK_CERT_F | SETUP_PLATFORM_CERT_F);
8✔
735

736
    ret = call_create_certs(flags, cert_flags, config_file, certsdir, ekparam,
8✔
737
                            vmid, &swtpm12->swtpm);
738
    if (ret != 0)
8✔
739
        return 1;
740

741
    for (idx = 0; flags_to_certfiles[idx].filename; idx++) {
24✔
742
        if (cert_flags & flags_to_certfiles[idx].flag) {
16✔
743
            SWTPM_G_FREE(filecontent);
15✔
744
            SWTPM_G_FREE(certfile);
15✔
745

746
            ret = read_certificate_file(certsdir, flags_to_certfiles[idx].filename,
15✔
747
                                        &filecontent, &filecontent_len, &certfile);
748
            if (ret != 0)
15✔
749
                return 1;
750

751
            if (flags_to_certfiles[idx].flag == SETUP_EK_CERT_F) {
15✔
752
                ret = swtpm12->ops->write_ek_cert_nvram(&swtpm12->swtpm,
8✔
753
                                                (const unsigned char*)filecontent, filecontent_len);
754
                if (ret == 0)
8✔
755
                    logit(gl_LOGFILE, "Successfully created NVRAM area for EK certificate.\n");
8✔
756
            } else {
757
                ret = swtpm12->ops->write_platform_cert_nvram(&swtpm12->swtpm,
7✔
758
                                                  (const unsigned char*)filecontent, filecontent_len);
759
                if (ret == 0)
7✔
760
                    logit(gl_LOGFILE, "Successfully created NVRAM area for Platform certificate.\n");
7✔
761
            }
762

763
            if (ret != 0) {
15✔
764
                unlink(certfile);
×
765
                return 1;
×
766
            }
767

768
            key_type = flags_to_certfiles[idx].flag & SETUP_EK_CERT_F ? "ek" : "";
15✔
769

770
            if (certfile_move_or_delete(flags, !!(flags_to_certfiles[idx].flag & SETUP_EK_CERT_F),
15✔
771
                                        certfile, user_certsdir, key_type, "rsa2048") != 0)
772
                return 1;
773
        }
774
    }
775

776
    return 0;
777
}
778

779
/* Simulate manufacturing a TPM 1.2: create keys and certificate and possibly take ownership */
780
static int init_tpm(unsigned long flags, gchar **swtpm_prg_l, const gchar *config_file,
26✔
781
                    const gchar *tpm_state_path, const gchar *ownerpass, const gchar *srkpass,
782
                    const gchar *vmid, const gchar *swtpm_keyopt,
783
                    int *fds_to_pass, size_t n_fds_to_pass, const gchar *certsdir,
784
                    const gchar *user_certsdir)
785
{
786
    struct swtpm12 *swtpm12;
26✔
787
    struct swtpm *swtpm;
26✔
788
    g_autofree gchar *pubek = NULL;
52✔
789
    size_t pubek_len = 0;
26✔
790
    int ret = 1;
26✔
791

792
    swtpm12 = swtpm12_new(swtpm_prg_l, tpm_state_path, swtpm_keyopt, gl_LOGFILE,
26✔
793
                          fds_to_pass, n_fds_to_pass);
794
    if (swtpm12 == NULL)
26✔
795
        return 1;
796
    swtpm = &swtpm12->swtpm;
26✔
797

798
    ret = swtpm->cops->start(swtpm);
26✔
799
    if (ret != 0) {
26✔
800
        logerr(gl_LOGFILE, "Could not start the TPM 1.2.\n");
×
801
        goto error;
×
802
    }
803

804
    ret = swtpm12->ops->run_swtpm_bios(swtpm);
26✔
805
    if (ret != 0)
26✔
806
         goto destroy;
×
807

808
    if ((flags & SETUP_CREATE_EK_F)) {
26✔
809
        ret = swtpm12->ops->create_endorsement_key_pair(swtpm, &pubek, &pubek_len);
19✔
810
        if (ret != 0)
19✔
811
            goto destroy;
×
812

813
        logit(gl_LOGFILE, "Successfully created EK.\n");
19✔
814

815
        /* can only take owernship if created an EK */
816
        if ((flags & SETUP_TAKEOWN_F)) {
19✔
817
            ret = tpm12_take_ownership(flags, ownerpass, srkpass, pubek, pubek_len, swtpm12);
9✔
818
            if (ret != 0)
9✔
819
                goto destroy;
×
820

821
            logit(gl_LOGFILE, "Successfully took ownership of the TPM.\n");
9✔
822
        }
823

824
        /* can only create EK cert if created an EK */
825
        if ((flags & SETUP_EK_CERT_F)) {
19✔
826
            g_autofree gchar *ekparam = print_as_hex((unsigned char *)pubek, pubek_len);
16✔
827

828
            ret = tpm12_create_certs(flags, config_file, certsdir, ekparam, vmid, swtpm12,
8✔
829
                                     user_certsdir);
830
            if (ret != 0)
8✔
831
                goto destroy;
×
832
        }
833
    }
834

835
    if ((flags & SETUP_LOCK_NVRAM_F)) {
26✔
836
        ret = swtpm12->ops->nv_lock(swtpm);
12✔
837
        if (ret == 0)
12✔
838
            logit(gl_LOGFILE, "Successfully locked NVRAM access.\n");
12✔
839
    }
840

841
destroy:
14✔
842
    swtpm->cops->destroy(swtpm);
26✔
843

844
error:
26✔
845
    swtpm_free(swtpm);
26✔
846

847
    return ret;
26✔
848
}
849

850
/* Check whether we are allowed to overwrite existing state.
851
 * This function returns 2 if the state exists but flag is set to not to overwrite it,
852
 * 0 in case we can overwrite it, 1 if the state exists.
853
 */
854
static int check_state_overwrite(const gchar **swtpm_prg_l, unsigned int flags,
151✔
855
                                 const char *tpm_state_path)
856
{
857
    gboolean success;
151✔
858
    g_autofree gchar *standard_output = NULL;
302✔
859
    int exit_status = 0;
151✔
860
    g_autoptr(GError) error = NULL;
151✔
861
    g_autofree const gchar **argv = NULL;
151✔
862
    g_autofree gchar *statearg = g_strdup_printf("backend-uri=%s", tpm_state_path);
302✔
863
    g_autofree gchar *logop = NULL;
151✔
864
    g_autofree const gchar **my_argv = NULL;
151✔
865

866
    my_argv = concat_arrays((const gchar*[]) {
151✔
867
                                "--print-states",
868
                                "--tpmstate",
869
                                statearg,
870
                                NULL
871
                            }, NULL, FALSE);
872

873
    if (flags & SETUP_TPM2_F)
151✔
874
        my_argv = concat_arrays(my_argv, (const gchar*[]) { "--tpm2", NULL }, TRUE);
122✔
875

876
    if (gl_LOGFILE != NULL) {
151✔
877
        logop = g_strdup_printf("file=%s", gl_LOGFILE);
87✔
878
        my_argv = concat_arrays(my_argv, (const gchar*[]){"--log", logop, NULL}, TRUE);
87✔
879
    }
880

881
    argv = concat_arrays(swtpm_prg_l, my_argv, FALSE);
151✔
882

883
    success = spawn_sync(NULL, argv, NULL, G_SPAWN_STDERR_TO_DEV_NULL, NULL, NULL,
151✔
884
                         &standard_output, NULL, &exit_status, &error);
885
    if (!success) {
151✔
886
        logerr(gl_LOGFILE, "Could not start swtpm '%s': %s\n", swtpm_prg_l[0], error->message);
×
887
        return 1;
×
888
    }
889

890
    if (exit_status != 0) {
151✔
891
        logerr(gl_LOGFILE, "%s exit with status %d: %s\n",
×
892
               swtpm_prg_l[0], exit_status, standard_output);
893
        return 1;
×
894
    }
895

896
    if (g_strstr_len(standard_output, -1, TPM_PERMANENT_ALL_NAME) != NULL) {
151✔
897
        /* State file exists */
898
        if (flags & SETUP_STATE_NOT_OVERWRITE_F) {
75✔
899
            logit(gl_LOGFILE, "Not overwriting existing state file.\n");
2✔
900
            return 2;
2✔
901
        }
902
        if (flags & SETUP_STATE_OVERWRITE_F)
73✔
903
            return 0;
904
        logerr(gl_LOGFILE, "Found existing TPM state '%s'.\n", TPM_PERMANENT_ALL_NAME);
3✔
905
        return 1;
3✔
906
    }
907

908
    return 0;
909
}
910

911
static void versioninfo(void)
2✔
912
{
913
    printf("TPM emulator setup tool version %d.%d.%d\n",
2✔
914
           SWTPM_VER_MAJOR, SWTPM_VER_MINOR, SWTPM_VER_MICRO);
915
}
2✔
916

917
static void usage(const char *prgname, const char *default_config_file)
1✔
918
{
919
    versioninfo();
1✔
920
    printf(
1✔
921
        "Usage: %s [options]\n"
922
        "\n"
923
        "The following options are supported:\n"
924
        "\n"
925
        "--runas <user>   : Run this program under the given user's account.\n"
926
        "\n"
927
        "--tpm-state <dir>: Path where the TPM's state will be written to;\n"
928
        "                   this is a mandatory argument. Prefix with dir:// to\n"
929
        "                   use directory backend, or file:// to use linear file.\n"
930
        "\n"
931
        "--tpmstate <dir> : This is an alias for --tpm-state <dir>.\n"
932
        "\n"
933
        "--tpm '<path-to-executable> socket'\n"
934
        "                 : Path to the TPM executable; this is an optional argument and\n"
935
        "                   by default 'swtpm' in the PATH is used.\n"
936
        "\n"
937
        "--swtpm_ioctl <executable>\n"
938
        "                 : Path to the swtpm_ioctl executable; this is deprecated\n"
939
        "                   argument.\n"
940
        "\n"
941
        "--tpm2           : Setup a TPM 2; by default a TPM 1.2 is setup.\n"
942
        "\n"
943
        "--createek       : Create the EK; for a TPM 2 an RSA and ECC EK will be\n"
944
        "                   created\n"
945
        "\n"
946
        "--allow-signing  : Create an EK that can be used for signing;\n"
947
        "                   this option requires --tpm2.\n"
948
        "                   Note: Careful, this option will create a non-standard EK!\n"
949
        "\n"
950
        "--decryption     : Create an EK that can be used for key encipherment;\n"
951
        "                   this is the default unless --allow-signing is given;\n"
952
        "                   this option requires --tpm2.\n"
953
        "\n"
954
        "--ecc            : This option allows to create a TPM 2's ECC key as storage\n"
955
        "                   primary key; a TPM 2 always gets an RSA and an ECC EK key.\n"
956
        "\n"
957
        "--take-ownership : Take ownership; this option implies --createek\n"
958
        "  --ownerpass  <password>\n"
959
        "                 : Provide custom owner password; default is %s\n"
960
        "  --owner-well-known:\n"
961
        "                 : Use an owner password of 20 zero bytes\n"
962
        "  --srkpass <password>\n"
963
        "                 : Provide custom SRK password; default is %s\n"
964
        "  --srk-well-known:\n"
965
        "                 : Use an SRK password of 20 zero bytes\n"
966
        "--create-ek-cert : Create an EK certificate; this implies --createek\n"
967
        "\n"
968
        "--create-platform-cert\n"
969
        "                 : Create a platform certificate; this implies --create-ek-cert\n"
970
        "\n"
971
        "--create-spk     : Create storage primary key; this requires --tpm2; deprecated\n"
972
        "\n"
973
        "--lock-nvram     : Lock NVRAM access\n"
974
        "\n"
975
        "--display        : At the end display as much info as possible about the\n"
976
        "                   configuration of the TPM\n"
977
        "\n"
978
        "--config <config file>\n"
979
        "                 : Path to configuration file; default is %s\n"
980
        "\n"
981
        "--logfile <logfile>\n"
982
        "                 : Path to log file; default is logging to stderr\n"
983
        "\n"
984
        "--keyfile <keyfile>\n"
985
        "                 : Path to a key file containing the encryption key for the\n"
986
        "                   TPM to encrypt its persistent state with. The content\n"
987
        "                   must be a 32 hex digit number representing a 128bit AES key.\n"
988
        "                   This parameter will be passed to the TPM using\n"
989
        "                   '--key file=<file>'.\n"
990
        "\n"
991
        "--keyfile-fd <fd>: Like --keyfile but a file descriptor is given to read the\n"
992
        "                   encryption key from.\n"
993
        "\n"
994
        "--pwdfile <pwdfile>\n"
995
        "                 : Path to a file containing a passphrase from which the\n"
996
        "                   TPM will derive the 128bit AES key. The passphrase can be\n"
997
        "                   32 bytes long.\n"
998
        "                   This parameter will be passed to the TPM using\n"
999
        "                   '--key pwdfile=<file>'.\n"
1000
        "\n"
1001
        "--pwdfile-fd <fd>: Like --pwdfile but a file descriptor is given to to read\n"
1002
        "                   the passphrase from.\n"
1003
        "\n"
1004
        "--cipher <cipher>: The cipher to use; either aes-128-cbc or aes-256-cbc;\n"
1005
        "                   the default is aes-128-cbc; the same cipher must be\n"
1006
        "                   used on the swtpm command line\n"
1007
        "\n"
1008
        "--overwrite      : Overwrite existing TPM state by re-initializing it; if this\n"
1009
        "                   option is not given, this program will return an error if\n"
1010
        "                   existing state is detected\n"
1011
        "\n"
1012
        "--not-overwrite  : Do not overwrite existing TPM state but silently end\n"
1013
        "\n"
1014
        "--vmid <vm id>   : Unique (VM) identifier to use as common name in certificate\n"
1015
        "\n"
1016
        "--pcr-banks <banks>\n"
1017
        "                 : Set of PCR banks to activate. Provide a comma separated list\n"
1018
        "                   like 'sha1,sha256'. '-' to skip and leave all banks active.\n"
1019
        "                   Default: %s\n"
1020
        "\n"
1021
        "--rsa-keysize <keysize>\n"
1022
        "                 : The RSA key size of the EK key; 3072 and 4096 bits may be\n"
1023
        "                   supported if libtpms supports it.\n"
1024
        "                   Default: %u\n"
1025
        "\n"
1026
        "--write-ek-cert-files <directory>\n"
1027
        "                 : Write EK cert files into the given directory\n"
1028
        "\n"
1029
        "--tcsd-system-ps-file <file>\n"
1030
        "                 : This option is deprecated and has no effect.\n"
1031
        "\n"
1032
        "--print-capabilities\n"
1033
        "                 : Print JSON formatted capabilities added after v0.1 and exit.\n"
1034
        "\n"
1035
        "--create-config-files [[overwrite][,root]]\n"
1036
        "                 : Create swtpm_setup and swtpm-localca config files for a\n"
1037
        "                   user account.\n"
1038
        "                   overwrite: overwrite any existing files\n"
1039
        "                   root: allow to create files under root's home directory\n"
1040
        "                   skip-if-exist: if any file exists exit without error\n"
1041
        "\n"
1042
        "--reconfigure    : Reconfigure an existing swtpm by reusing existing state.\n"
1043
        "                   The active PCR banks can be changed but no new keys will\n"
1044
        "                   be created.\n"
1045
        "\n"
1046
        "--profile <json-profile>\n"
1047
        "                 : Configure swtpm with the given profile.\n"
1048
        "\n"
1049
        "--profile-name <profile name | built-in profile name>\n"
1050
        "                 : Search for a profile with the <name>.json in distro and\n"
1051
        "                   local directories; if not found try it as a built-in.\n"
1052
        "\n"
1053
        "--profile-file <file>\n"
1054
        "                 : Configure swtpm with a profile read from the given file.\n"
1055
        "\n"
1056
        "--profile-file-fd <fd>\n"
1057
        "                 : Configure swtpm with a profile read from a file descriptor.\n"
1058
        "\n"
1059
        "--profile-remove-disabled check|fips-host\n"
1060
        "                 : Instruct swtpm to remove algorithms that may be disabled by\n"
1061
        "                   FIPS mode on the host from 'custom' profile.\n"
1062
        "                   check: algorithms are tested.\n"
1063
        "                   fips-host: no testing.\n"
1064
        "\n"
1065
        "--print-profiles : Display all local and distro-provided profile as well as\n"
1066
        "                   the ones built into libtpms and exit.\n"
1067
        "\n"
1068
        "--version        : Display version and exit\n"
1069
        "\n"
1070
        "--help,-h        : Display this help screen\n\n",
1071
            prgname,
1072
            DEFAULT_OWNER_PASSWORD,
1073
            DEFAULT_SRK_PASSWORD,
1074
            default_config_file,
1075
            DEFAULT_PCR_BANKS,
1076
            DEFAULT_RSA_KEYSIZE
1077
        );
1078
}
1✔
1079

1080
static int get_swtpm_capabilities(const gchar **swtpm_prg_l, gboolean is_tpm2,
397✔
1081
                                  gchar **standard_output)
1082
{
1083
    const gchar *my_argv[] = { "--print-capabilities", is_tpm2 ? "--tpm2" : NULL, NULL };
397✔
1084
    g_autofree gchar *standard_error = NULL;
794✔
1085
    g_autofree gchar *logop = NULL;
397✔
1086
    g_autoptr(GError) error = NULL;
397✔
1087
    g_autofree const gchar **argv = NULL;
397✔
1088
    int exit_status = 0;
397✔
1089
    gboolean success;
397✔
1090
    int ret = 1;
397✔
1091

1092
    argv = concat_arrays(swtpm_prg_l, my_argv, FALSE);
397✔
1093

1094
    if (gl_LOGFILE != NULL) {
397✔
1095
        logop = g_strdup_printf("file=%s", gl_LOGFILE);
248✔
1096
        argv = concat_arrays(argv, (const gchar*[]){"--log", logop, NULL}, TRUE);
248✔
1097
    }
1098

1099
    success = spawn_sync(NULL, argv, NULL, 0, NULL, NULL,
397✔
1100
                         standard_output, &standard_error, &exit_status, &error);
1101
    if (!success) {
397✔
1102
        logerr(gl_LOGFILE, "Could not start swtpm '%s': %s\n", swtpm_prg_l[0], error->message);
×
1103
        goto error;
×
1104
    }
1105
    if (exit_status != 0) {
397✔
1106
        /* possible: failure to access log file */
1107
        logerr(gl_LOGFILE, "Failed to run swtpm '%s': %s\n", swtpm_prg_l[0], standard_error);
×
1108
        goto error;
×
1109
    }
1110
    ret = 0;
1111

1112
error:
397✔
1113
    return ret;
397✔
1114
}
1115

1116
static int get_supported_tpm_versions(const gchar **swtpm_prg_l, gboolean *swtpm_has_tpm12,
169✔
1117
                                      gboolean *swtpm_has_tpm2)
1118
{
1119
    g_autofree gchar *standard_output = NULL;
338✔
1120
    int ret;
169✔
1121

1122
    ret = get_swtpm_capabilities(swtpm_prg_l, FALSE, &standard_output);
169✔
1123
    if (ret)
169✔
1124
        return ret;
1125

1126
    *swtpm_has_tpm12 = g_strstr_len(standard_output, -1, "\"tpm-1.2\"") != NULL;
169✔
1127
    *swtpm_has_tpm2 = g_strstr_len(standard_output, -1, "\"tpm-2.0\"") != NULL;
169✔
1128

1129
    return 0;
169✔
1130
}
1131

1132
/* Get the support RSA key sizes.
1133
 *  This function returns an array of ints like the following
1134
 *  - [ 1024, 2048, 3072, 4096 ]
1135
 *  - [] (empty array, indicating only 2048 bit RSA keys are supported)
1136
 */
1137
static int get_rsa_keysizes(unsigned long flags, const gchar **swtpm_prg_l,
160✔
1138
                            unsigned int **keysizes, size_t *n_keysizes)
1139
{
1140
    g_autofree gchar *standard_output = NULL;
320✔
1141
    const gchar *needle = "\"rsa-keysize-";
160✔
1142
    unsigned int keysize;
160✔
1143
    int ret = 1;
160✔
1144
    char *p;
160✔
1145
    int n;
160✔
1146

1147
    *n_keysizes = 0;
160✔
1148

1149
    if (flags & SETUP_TPM2_F) {
160✔
1150
        ret = get_swtpm_capabilities(swtpm_prg_l, TRUE, &standard_output);
134✔
1151
        if (ret)
134✔
1152
            goto error;
×
1153

1154
        p = standard_output;
134✔
1155
        /* A crude way of parsing the json output just looking for "rsa-keysize-%u" */
1156
        while ((p = g_strstr_len(p, -1, needle)) != NULL) {
670✔
1157
            p += strlen(needle);
536✔
1158
            n = sscanf(p, "%u\"", &keysize);
536✔
1159
            if (n == 1) {
536✔
1160
                *keysizes = g_realloc(*keysizes, (*n_keysizes + 1) * sizeof(unsigned int));
536✔
1161
                (*keysizes)[*n_keysizes] = keysize;
536✔
1162
                (*n_keysizes)++;
536✔
1163
            }
1164
        }
1165
    }
1166
    ret = 0;
1167

1168
error:
160✔
1169
    return ret;
160✔
1170
}
1171

1172
/* Return the RSA key size capabilities in a NULL-terminated array */
1173
static int get_rsa_keysize_caps(unsigned long flags, const gchar **swtpm_prg_l,
9✔
1174
                                gchar ***keysize_strs)
1175
{
1176
    unsigned int *keysizes = NULL;
9✔
1177
    size_t n_keysizes = 0;
9✔
1178
    size_t i, j;
9✔
1179
    int ret = get_rsa_keysizes(flags, swtpm_prg_l, &keysizes, &n_keysizes);
9✔
1180
    if (ret)
9✔
1181
        return ret;
1182

1183
    *keysize_strs = g_malloc0(sizeof(char *) * (n_keysizes + 1));
9✔
1184
    for (i = 0, j = 0; i < n_keysizes; i++) {
45✔
1185
        if (keysizes[i] >= 2048)
36✔
1186
            (*keysize_strs)[j++] = g_strdup_printf("tpm2-rsa-keysize-%u", keysizes[i]);
27✔
1187
    }
1188

1189
    g_free(keysizes);
9✔
1190

1191
    return 0;
9✔
1192
}
1193

1194
static int validate_json_profile(const gchar **swtpm_prg_l, const char *json_profile)
85✔
1195
{
1196
    g_autofree gchar *standard_output = NULL;
170✔
1197
    int ret;
85✔
1198

1199
    ret = get_swtpm_capabilities(swtpm_prg_l, TRUE, &standard_output);
85✔
1200
    if (ret)
85✔
1201
        return ret;
1202

1203
    return check_json_profile(standard_output, json_profile);
85✔
1204
}
1205

1206
/* Print the JSON object of swtpm_setup's capabilities */
1207
static int print_capabilities(const char **swtpm_prg_l, gboolean swtpm_has_tpm12,
9✔
1208
                              gboolean swtpm_has_tpm2)
1209
{
1210
    g_autofree gchar *standard_output = NULL;
18✔
1211
    g_autofree gchar *param = g_strdup("");
18✔
1212
    g_autofree gchar *profile_list = NULL;
9✔
1213
    gchar **profile_names = NULL;
9✔
1214
    gchar **keysize_strs = NULL;
9✔
1215
    gchar *tmp;
9✔
1216
    size_t i;
9✔
1217
    int ret = 0;
9✔
1218

1219
    ret = get_rsa_keysize_caps(SETUP_TPM2_F, swtpm_prg_l, &keysize_strs);
9✔
1220
    if (ret)
9✔
1221
        return 1;
1222

1223
    for (i = 0; keysize_strs[i] != NULL; i++) {
36✔
1224
        tmp = g_strdup_printf("%s, \"%s\"", param, keysize_strs[i]);
27✔
1225
        g_free(param);
27✔
1226
        param = tmp;
27✔
1227
    }
1228

1229
    if (swtpm_has_tpm2) {
9✔
1230
        ret = get_swtpm_capabilities(swtpm_prg_l, TRUE, &standard_output);
9✔
1231
        if (ret)
9✔
1232
            goto error;
×
1233
        ret = get_profile_names(standard_output, &profile_names);
9✔
1234
        if (ret)
9✔
1235
            goto error;
×
1236

1237
        if (g_strv_length(profile_names) > 0) {
9✔
1238
            tmp = g_strjoinv("\", \"", profile_names);
9✔
1239
            profile_list = g_strdup_printf(" \"%s\" ", tmp);
9✔
1240
            g_free(tmp);
9✔
1241
        }
1242
    }
1243

1244
    printf("{ \"type\": \"swtpm_setup\", "
9✔
1245
           "\"features\": [ %s%s\"cmdarg-keyfile-fd\", \"cmdarg-pwdfile-fd\", \"tpm12-not-need-root\""
1246
           ", \"cmdarg-write-ek-cert-files\", \"cmdarg-create-config-files\""
1247
           ", \"cmdarg-reconfigure-pcr-banks\""
1248
           "%s"
1249
           ", \"cmdarg-profile\", \"cmdarg-profile-remove-disabled\""
1250
           ""
1251
           " ], "
1252
           "\"profiles\": [%s], "
1253
           "\"version\": \"" VERSION "\" "
1254
           "}\n",
1255
           swtpm_has_tpm12 ? "\"tpm-1.2\", " : "",
1256
           swtpm_has_tpm2  ? "\"tpm-2.0\", " : "",
1257
           param,
1258
           profile_list ? profile_list : ""
1259
           );
1260

1261
error:
9✔
1262
    g_strfreev(keysize_strs);
9✔
1263
    g_strfreev(profile_names);
9✔
1264

1265
    return ret;
9✔
1266
}
1267

1268
static int change_process_owner(const char *user)
1269
{
1270
    char *endptr;
×
1271
    unsigned long long uid = strtoull(user, &endptr, 10);
×
1272
    gid_t gid;
×
1273
    struct passwd *passwd;
×
1274
    int ret = 1;
×
1275

1276
    if (*endptr != '\0') {
×
1277
        /* assuming a name */
1278
        passwd = getpwnam(user);
×
1279
        if (passwd == NULL) {
×
1280
            logerr(gl_LOGFILE, "Error: User '%s' does not exist.\n", user);
×
1281
            goto error;
×
1282
        }
1283

1284
        if (initgroups(passwd->pw_name, passwd->pw_gid) != 0) {
×
1285
            logerr(gl_LOGFILE, "Error: initgroups() failed: %s\n", strerror(errno));
×
1286
            goto error;
×
1287
        }
1288

1289
        gid = passwd->pw_gid;
×
1290
        uid = passwd->pw_uid;
×
1291
    } else {
1292
        if (uid > 0xffffffff) {
×
1293
            logerr(gl_LOGFILE, "Error: uid %s outside valid range.\n", user);
×
1294
            goto error;
×
1295
        }
1296
        gid = (gid_t)uid;
×
1297
    }
1298

1299
    if (setgid(gid) != 0) {
×
1300
        logerr(gl_LOGFILE, "Error: setgid(%d) failed: %s\n", gid, strerror(errno));
×
1301
        goto error;
×
1302
    }
1303

1304
    if (setuid(uid) != 0) {
×
1305
        logerr(gl_LOGFILE, "Error: setuid(%d) failed: %s\n", uid, strerror(errno));
×
1306
        goto error;
×
1307
    }
1308

1309
    ret = 0;
1310

1311
error:
×
1312
    return ret;
×
1313
}
1314

1315
static int handle_create_config_files(const char *opt_arg)
1316
{
1317
    g_auto(GStrv) tokens = NULL;
×
1318
    gboolean overwrite = FALSE;
×
1319
    gboolean root_flag = FALSE;
×
1320
    gboolean skip_if_exist = FALSE;
×
1321

1322
    if (opt_arg) {
×
1323
        tokens = g_strsplit_set(opt_arg, ", ", -1);
×
1324
        overwrite = g_strv_contains((const gchar **)tokens, "overwrite");
×
1325
        root_flag = g_strv_contains((const gchar **)tokens, "root");
×
1326
        skip_if_exist = g_strv_contains((const gchar **)tokens, "skip-if-exist");
×
1327
        if (overwrite && skip_if_exist) {
×
1328
            fprintf(stderr, "Error: overwrite and skip-if-exist cannot both be used\n");
×
1329
            return 1;
×
1330
        }
1331
    }
1332

1333
    return create_config_files(overwrite, root_flag, skip_if_exist);
×
1334
}
1335

1336
static int read_config_file(const gchar *config_file,
155✔
1337
                            const struct passwd *user,
1338
                            gchar ***config_file_lines)
1339
{
1340
    if (access(config_file, R_OK) != 0) {
155✔
1341
        logerr(gl_LOGFILE, "User %s cannot read config file %s.\n",
×
1342
               user ? user->pw_name : "<unknown>", config_file);
1343
        return -1;
×
1344
    }
1345

1346
    if (read_file_lines(config_file, config_file_lines))
155✔
1347
        return -1;
×
1348

1349
    return 0;
1350
}
1351

1352
int main(int argc, char *argv[])
182✔
1353
{
1354
    int opt, option_index = 0;
182✔
1355
    static const struct option long_options[] = {
182✔
1356
        {"tpm-state", required_argument, NULL, 't'},
1357
        {"tpmstate", required_argument, NULL, 't'}, /* alias for tpm-state */
1358
        {"tpm", required_argument, NULL, 'T'},
1359
        {"swtpm_ioctl", required_argument, NULL, '_'},
1360
        {"tpm2", no_argument, NULL, '2'},
1361
        {"ecc", no_argument, NULL, 'e'},
1362
        {"createek", no_argument, NULL, 'c'},
1363
        {"create-spk", no_argument, NULL, 'C'},
1364
        {"take-ownership", no_argument, NULL, 'o'},
1365
        {"ownerpass", required_argument, NULL, 'O'},
1366
        {"owner-well-known", no_argument, NULL, 'w'},
1367
        {"srkpass", required_argument, NULL, 'S'},
1368
        {"srk-well-known", no_argument, NULL, 's'},
1369
        {"create-ek-cert", no_argument, NULL, 'E'},
1370
        {"create-platform-cert", no_argument, NULL, 'P'},
1371
        {"lock-nvram", no_argument, NULL, 'L'},
1372
        {"display", no_argument, NULL, 'i'},
1373
        {"config", required_argument, NULL, 'f'},
1374
        {"vmid", required_argument, NULL, 'm'},
1375
        {"keyfile", required_argument, NULL, 'x'},
1376
        {"keyfile-fd", required_argument, NULL, 'X'},
1377
        {"pwdfile", required_argument, NULL, 'k'},
1378
        {"pwdfile-fd", required_argument, NULL, 'K'},
1379
        {"cipher", required_argument, NULL, 'p'},
1380
        {"runas", required_argument, NULL, 'r'},
1381
        {"logfile", required_argument, NULL, 'l'},
1382
        {"overwrite", no_argument, NULL, 'v'},
1383
        {"not-overwrite", no_argument, NULL, 'V'},
1384
        {"allow-signing", no_argument, NULL, 'a'},
1385
        {"decryption", no_argument, NULL, 'd'},
1386
        {"pcr-banks", required_argument, NULL, 'b'},
1387
        {"rsa-keysize", required_argument, NULL, 'A'},
1388
        {"write-ek-cert-files", required_argument, NULL, '3'},
1389
        {"create-config-files", optional_argument, NULL, 'u'},
1390
        {"tcsd-system-ps-file", required_argument, NULL, 'F'},
1391
        {"version", no_argument, NULL, '1'},
1392
        {"print-capabilities", no_argument, NULL, 'y'},
1393
        {"reconfigure", no_argument, NULL, 'R'},
1394
        {"profile", required_argument, NULL, 'I'},
1395
        {"profile-name", required_argument, NULL, 'J'},
1396
        {"profile-file", required_argument, NULL, 'g'},
1397
        {"profile-file-fd", required_argument, NULL, 'G'},
1398
        {"profile-remove-disabled", required_argument, NULL, 'j'},
1399
        {"print-profiles", no_argument, NULL, 'M'},
1400
        {"help", no_argument, NULL, 'h'},
1401
        {NULL, 0, NULL, 0}
1402
    };
1403
    unsigned long flags = 0;
182✔
1404
    g_auto(GStrv) config_file_lines = NULL;
182✔
1405
    g_autofree gchar *swtpm_prg = NULL;
182✔
1406
    g_autofree gchar *tpm_state_path = NULL;
182✔
1407
    struct swtpm_backend_ops *backend_ops = &swtpm_backend_dir;
182✔
1408
    void *backend_state = NULL;
182✔
1409
    g_autofree gchar *config_file = NULL;
182✔
1410
    g_autofree gchar *ownerpass = NULL;
182✔
1411
    gboolean got_ownerpass = FALSE;
182✔
1412
    g_autofree gchar *srkpass = NULL;
182✔
1413
    gboolean got_srkpass = FALSE;
182✔
1414
    g_autofree gchar *vmid = NULL;
182✔
1415
    g_autofree gchar *pcr_banks = NULL;
182✔
1416
    gboolean printcapabilities = FALSE;
182✔
1417
    gboolean printprofiles = FALSE;
182✔
1418
    g_autofree gchar *keyfile = NULL;
182✔
1419
    long int keyfile_fd = -1;
182✔
1420
    g_autofree gchar *pwdfile = NULL;
182✔
1421
    long int pwdfile_fd = -1;
182✔
1422
    g_autofree gchar *cipher = g_strdup("aes-128-cbc");
364✔
1423
    g_autofree gchar *rsa_keysize_str = NULL;
182✔
1424
    unsigned int rsa_keysize;
182✔
1425
    g_autofree gchar *swtpm_keyopt = NULL;
182✔
1426
    g_autofree gchar *runas = NULL;
182✔
1427
    g_autofree gchar *certsdir = NULL;
182✔
1428
    g_autofree gchar *user_certsdir = NULL;
182✔
1429
    g_autofree gchar *json_profile = NULL;
182✔
1430
    g_autofree gchar *json_profile_name = NULL;
182✔
1431
    g_autofree gchar *json_profile_file = NULL;
182✔
1432
    g_autofree gchar *profile_remove_disabled_param = NULL;
182✔
1433
    int json_profile_fd = -1;
182✔
1434
    gchar *tmp;
182✔
1435
    gchar **swtpm_prg_l = NULL;
182✔
1436
    gchar **tmp_l = NULL;
182✔
1437
    size_t i, n;
182✔
1438
    struct stat statbuf;
182✔
1439
    const struct passwd *curr_user;
182✔
1440
    struct group *curr_grp;
182✔
1441
    char *endptr;
182✔
1442
    gboolean swtpm_has_tpm12 = FALSE;
182✔
1443
    gboolean swtpm_has_tpm2 = FALSE;
182✔
1444
    int fds_to_pass[2] = { -1, -1 };
182✔
1445
    unsigned n_fds_to_pass = 0;
182✔
1446
    char tmpbuffer[200];
182✔
1447
    time_t now;
182✔
1448
    struct tm *tm;
182✔
1449
    int ret = 1;
182✔
1450
    g_autoptr(GError) error = NULL;
182✔
1451

1452
    setvbuf(stdout, 0, _IONBF, 0);
182✔
1453

1454
    if (init(&config_file) < 0)
182✔
1455
        goto error;
×
1456

1457
    swtpm_prg = g_find_program_in_path("swtpm");
182✔
1458
    if (swtpm_prg) {
182✔
1459
        tmp = g_strconcat(swtpm_prg, " socket", NULL);
68✔
1460
        g_free(swtpm_prg);
68✔
1461
        swtpm_prg = tmp;
68✔
1462
    }
1463

1464
    while ((opt = getopt_long(argc, argv, "h?",
3,092✔
1465
                              long_options, &option_index)) != -1) {
1,546✔
1466
        switch (opt) {
1,366✔
1467
        case 't': /* --tpmstate, --tpm-state */
167✔
1468
            g_free(tpm_state_path);
167✔
1469
            if (strncmp(optarg, "dir://", 6) == 0) {
167✔
1470
                tpm_state_path = g_strdup(optarg);
10✔
1471
            } else if (strncmp(optarg, "file://", 7) == 0) {
157✔
1472
                tpm_state_path = g_strdup(optarg);
3✔
1473
                backend_ops = &swtpm_backend_file;
3✔
1474
            } else {
1475
                /* always prefix with dir:// so we can pass verbatim to swtpm */
1476
                tpm_state_path = g_strconcat("dir://", optarg, NULL);
154✔
1477
            }
1478
            break;
1479
        case 'T': /* --tpm */
165✔
1480
            g_free(swtpm_prg);
165✔
1481
            swtpm_prg = g_strdup(optarg);
165✔
1482
            break;
165✔
1483
        case '_': /* --swtpm_ioctl */
×
1484
            fprintf(stdout, "Warning: --swtpm_ioctl is deprecated and has no effect.");
×
1485
            break;
1486
        case '2': /* --tpm2 */
144✔
1487
            flags |= SETUP_TPM2_F;
144✔
1488
            break;
144✔
1489
        case 'e': /* --ecc */
16✔
1490
            flags |= SETUP_TPM2_ECC_F;
16✔
1491
            break;
16✔
1492
        case 'c': /* --createek */
50✔
1493
            flags |= SETUP_CREATE_EK_F;
50✔
1494
            break;
50✔
1495
        case 'C': /* --create-spk */
5✔
1496
            flags |= SETUP_CREATE_SPK_F;
5✔
1497
            break;
5✔
1498
        case 'o': /* --take-ownership */
10✔
1499
            flags |= SETUP_CREATE_EK_F | SETUP_TAKEOWN_F;
10✔
1500
            break;
10✔
1501
        case 'O': /* --ownerpass */
2✔
1502
            g_free(ownerpass);
2✔
1503
            ownerpass = g_strdup(optarg);
2✔
1504
            got_ownerpass = TRUE;
2✔
1505
            break;
2✔
1506
        case 'w': /* --owner-well-known */
2✔
1507
            flags |= SETUP_OWNERPASS_ZEROS_F;
2✔
1508
            got_ownerpass = TRUE;
2✔
1509
            break;
2✔
1510
        case 'S': /* --srk-pass */
2✔
1511
            g_free(srkpass);
2✔
1512
            srkpass = g_strdup(optarg);
2✔
1513
            got_srkpass = TRUE;
2✔
1514
            break;
2✔
1515
        case 's': /* --srk-well-known */
2✔
1516
            flags |= SETUP_SRKPASS_ZEROS_F;
2✔
1517
            got_srkpass = TRUE;
2✔
1518
            break;
2✔
1519
        case 'E': /* --create-ek-cert */
48✔
1520
            flags |= SETUP_CREATE_EK_F | SETUP_EK_CERT_F;
48✔
1521
            break;
48✔
1522
        case 'P': /* --create-platform-cert */
46✔
1523
            flags |= SETUP_CREATE_EK_F | SETUP_PLATFORM_CERT_F;
46✔
1524
            break;
46✔
1525
        case 'L': /* --lock-nvram */
16✔
1526
            flags |= SETUP_LOCK_NVRAM_F;
16✔
1527
            break;
16✔
1528
        case 'i': /* --display */
40✔
1529
            flags |= SETUP_DISPLAY_RESULTS_F;
40✔
1530
            break;
40✔
1531
        case 'f': /* --config */
203✔
1532
            g_free(config_file);
203✔
1533
            config_file = g_strdup(optarg);
203✔
1534
            break;
203✔
1535
        case 'm': /* --vmid */
41✔
1536
            g_free(vmid);
41✔
1537
            vmid = g_strdup(optarg);
41✔
1538
            break;
41✔
1539
        case 'x': /* --keyfile */
12✔
1540
            g_free(keyfile);
12✔
1541
            keyfile = g_strdup(optarg);
12✔
1542
            break;
12✔
1543
        case 'X': /* --pwdfile-fd' */
2✔
1544
            keyfile_fd = strtoull(optarg, &endptr, 10);
2✔
1545
            if (*endptr != '\0' && keyfile_fd >= INT_MAX) {
2✔
1546
                fprintf(stderr, "Invalid file descriptor '%s'\n", optarg);
×
1547
                goto error;
×
1548
            }
1549
            break;
1550
        case 'k': /* --pwdfile */
17✔
1551
            g_free(pwdfile);
17✔
1552
            pwdfile = g_strdup(optarg);
17✔
1553
            break;
17✔
1554
        case 'K': /* --pwdfile-fd' */
2✔
1555
            pwdfile_fd = strtoull(optarg, &endptr, 10);
2✔
1556
            if (*endptr != '\0' || pwdfile_fd >= INT_MAX) {
2✔
1557
                fprintf(stderr, "Invalid file descriptor '%s'\n", optarg);
×
1558
                goto error;
×
1559
            }
1560
            break;
1561
        case 'p': /* --cipher */
14✔
1562
            g_free(cipher);
14✔
1563
            cipher = g_strdup(optarg);
14✔
1564
            break;
14✔
1565
        case 'r': /* --runas */
×
1566
            g_free(runas);
×
1567
            runas = g_strdup(optarg);
×
1568
            break;
×
1569
        case 'l': /* --logfile */
93✔
1570
            g_free(gl_LOGFILE);
93✔
1571
            gl_LOGFILE = g_strdup(optarg);
93✔
1572
            break;
93✔
1573
        case 'v': /* --overwrite */
90✔
1574
            flags |= SETUP_STATE_OVERWRITE_F;
90✔
1575
            break;
90✔
1576
        case 'V': /* --not-overwrite */
3✔
1577
            flags |= SETUP_STATE_NOT_OVERWRITE_F;
3✔
1578
            break;
3✔
1579
        case 'a': /* --allow-signing */
25✔
1580
            flags |= SETUP_ALLOW_SIGNING_F;
25✔
1581
            break;
25✔
1582
        case 'd': /* --decryption */
8✔
1583
            flags |= SETUP_DECRYPTION_F;
8✔
1584
            break;
8✔
1585
        case 'b': /* --pcr-banks */
9✔
1586
            tmp = g_strconcat(pcr_banks ? pcr_banks: "",
27✔
1587
                              pcr_banks ? "," : "", g_strstrip(optarg), NULL);
1588
            g_free(pcr_banks);
9✔
1589
            pcr_banks = tmp;
9✔
1590
            break;
9✔
1591
        case 'A': /* --rsa-keysize */
21✔
1592
            g_free(rsa_keysize_str);
21✔
1593
            rsa_keysize_str = strdup(optarg);
21✔
1594
            flags |= SETUP_RSA_KEYSIZE_BY_USER_F;
21✔
1595
            break;
21✔
1596
        case '3': /* --write-ek-cert-files */
6✔
1597
            g_free(user_certsdir);
6✔
1598
            user_certsdir = g_strdup(optarg);
6✔
1599
            flags |= SETUP_WRITE_EK_CERT_FILES_F;
6✔
1600
            break;
6✔
1601
        case 'u':
×
1602
            if (optarg == NULL && optind < argc && argv[optind][0] != '0')
×
1603
                optarg = argv[optind++];
×
1604
            ret = handle_create_config_files(optarg);
×
1605
            goto out;
×
1606
        case 'F': /* --tcsd-system-ps-file */
1607
            printf("Warning: --tcsd-system-ps-file is deprecated and has no effect.");
1,546✔
1608
            break;
1609
        case '1': /* --version */
1✔
1610
            versioninfo();
1✔
1611
            ret = 0;
1✔
1612
            goto out;
1✔
1613
        case 'y': /* --print-capabilities */
1614
            printcapabilities = TRUE;
1615
            break;
1616
        case 'R': /* --reconfigure */
8✔
1617
            flags |= SETUP_RECONFIGURE_F;
8✔
1618
            break;
8✔
1619
        case 'I': /* --profile */
60✔
1620
            g_free(json_profile);
60✔
1621
            json_profile = g_strdup(optarg);
60✔
1622
            break;
60✔
1623
        case 'J': /* --profile-name */
16✔
1624
            g_free(json_profile_name);
16✔
1625
            json_profile_name = g_strdup(optarg);
16✔
1626
            break;
16✔
1627
        case 'g': /* --profile-file */
1✔
1628
            g_free(json_profile_file);
1✔
1629
            json_profile_file = g_strdup(optarg);
1✔
1630
            break;
1✔
1631
        case 'G': /* --profile-file-fd */
×
1632
            json_profile_fd = strtoull(optarg, &endptr, 10);
×
1633
            if (*endptr != '\0' || json_profile_fd >= INT_MAX) {
×
1634
                fprintf(stderr, "Invalid file descriptor '%s'\n", optarg);
×
1635
                goto error;
×
1636
            }
1637
            break;
1638
        case 'j': /* --profile-remove-disabled */
6✔
1639
            if (strcmp(optarg, "fips-host") != 0 &&
6✔
1640
                strcmp(optarg, "check") != 0) {
×
1641
                fprintf(stderr,
×
1642
                        "Unsupported parameter for --profile-remove-disabled: %s\n",
1643
                        optarg);
1644
                goto error;
×
1645
            }
1646
            g_free(profile_remove_disabled_param);
6✔
1647
            profile_remove_disabled_param = g_strdup(optarg);
6✔
1648
            break;
6✔
1649
        case 'M': /* --print-profiles */
3✔
1650
            printprofiles = TRUE;
3✔
1651
            break;
3✔
1652
        case '?':
1✔
1653
        case 'h': /* --help */
1654
            usage(argv[0], config_file);
1✔
1655
            if (opt == 'h')
1✔
1656
                ret = 0;
1✔
1657
            goto out;
1✔
1658
        default:
×
1659
            fprintf(stderr, "Unknown option code %d\n", opt);
×
1660
            usage(argv[0], config_file);
×
1661
            goto error;
×
1662
        }
1663
    }
1664

1665
    if (swtpm_prg == NULL) {
180✔
1666
        logerr(gl_LOGFILE,
11✔
1667
               "Default TPM 'swtpm' could not be found and was not provided using --tpm.\n");
1668
        goto error;
11✔
1669
    }
1670

1671
    swtpm_prg_l = split_cmdline(swtpm_prg);
169✔
1672
    tmp = g_find_program_in_path(swtpm_prg_l[0]);
169✔
1673
    if (!tmp) {
169✔
1674
        logerr(gl_LOGFILE, "swtpm at %s is not an executable.\n", swtpm_prg_l[0]);
×
1675
        goto error;
×
1676
    }
1677
    g_free(tmp);
169✔
1678

1679
    ret = get_supported_tpm_versions((const char **)swtpm_prg_l, &swtpm_has_tpm12, &swtpm_has_tpm2);
169✔
1680
    if (ret != 0)
169✔
1681
        goto error;
×
1682

1683
    if (printcapabilities) {
169✔
1684
        ret = print_capabilities((const char **)swtpm_prg_l, swtpm_has_tpm12, swtpm_has_tpm2);
9✔
1685
        goto out;
9✔
1686
    }
1687

1688
    if ((flags & SETUP_TPM2_F) != 0 && !swtpm_has_tpm2) {
160✔
1689
        logerr(gl_LOGFILE, "swtpm at %s does not support TPM 2\n", swtpm_prg_l[0]);
×
1690
        goto error;
×
1691
    } else if ((flags & SETUP_TPM2_F) == 0 && !swtpm_has_tpm12){
160✔
1692
        logerr(gl_LOGFILE, "swtpm at %s does not support TPM 1.2\n", swtpm_prg_l[0]);
×
1693
        goto error;
×
1694
    }
1695

1696
    if (runas) {
160✔
1697
        ret = change_process_owner(runas);
×
1698
        if (ret != 0)
×
1699
            goto error;
×
1700
    }
1701

1702
    curr_user = getpwuid(getuid());
160✔
1703

1704
    if (printprofiles) {
160✔
1705
        ret = 0;
3✔
1706
        if (read_config_file(config_file, curr_user, &config_file_lines) < 0)
3✔
1707
            goto error;
×
1708

1709
        if (flags & SETUP_TPM2_F) {
3✔
1710
            if (profile_printall((const char **)swtpm_prg_l, config_file_lines))
3✔
1711
                ret = 1;
3✔
1712
        } else {
1713
            printf("{}\n");
×
1714
        }
1715
        goto out;
3✔
1716
    }
1717

1718
    if (!got_ownerpass)
157✔
1719
        ownerpass = g_strdup(DEFAULT_OWNER_PASSWORD);
153✔
1720
    if (!got_srkpass)
157✔
1721
        srkpass = g_strdup(DEFAULT_SRK_PASSWORD);
153✔
1722

1723
    if (gl_LOGFILE != NULL) {
157✔
1724
        FILE *tmpfile;
93✔
1725
        if (stat(gl_LOGFILE, &statbuf) == 0 &&
93✔
1726
            (statbuf.st_mode & S_IFMT) == S_IFLNK) {
93✔
1727
            fprintf(stderr, "Logfile must not be a symlink.\n");
×
1728
            goto error;
×
1729
        }
1730
        tmpfile = fopen(gl_LOGFILE, "a");
93✔
1731
        if (tmpfile == NULL) {
93✔
1732
            fprintf(stderr, "Cannot write to logfile %s.\n", gl_LOGFILE);
×
1733
            goto error;
×
1734
        }
1735
        fclose(tmpfile);
93✔
1736
    }
1737

1738
    // Check tpm_state_path directory and access rights
1739
    if (tpm_state_path == NULL) {
157✔
1740
        logerr(gl_LOGFILE, "--tpm-state must be provided\n");
×
1741
        goto error;
×
1742
    }
1743

1744
    backend_state = backend_ops->parse_backend(tpm_state_path);
157✔
1745
    if (!backend_state)
157✔
1746
        goto error;
×
1747

1748
    if (backend_ops->check_access(backend_state, R_OK|W_OK, curr_user) != 0)
157✔
1749
        goto error;
×
1750

1751
    if ((flags & SETUP_WRITE_EK_CERT_FILES_F)) {
157✔
1752
        if (check_directory_access(user_certsdir, W_OK, curr_user) != 0)
6✔
1753
            goto error;
×
1754
    }
1755

1756
    if (flags & SETUP_TPM2_F) {
157✔
1757
        if (flags & SETUP_TAKEOWN_F) {
128✔
1758
            logerr(gl_LOGFILE, "Taking ownership is not supported for TPM 2.\n");
×
1759
            goto error;
×
1760
        }
1761
    } else {
1762
        if (flags & SETUP_TPM2_ECC_F) {
29✔
1763
            logerr(gl_LOGFILE, "--ecc requires --tpm2.\n");
×
1764
            goto error;
×
1765
        }
1766
        if (flags & SETUP_CREATE_SPK_F) {
29✔
1767
            logerr(gl_LOGFILE, "--create-spk requires --tpm2.\n");
×
1768
            goto error;
×
1769
        }
1770
        if (flags & SETUP_RECONFIGURE_F) {
29✔
1771
            logerr(gl_LOGFILE, "--reconfigure requires --tpm2.\n");
×
1772
            goto error;
×
1773
        }
1774
        if (flags & SETUP_ALLOW_SIGNING_F) {
29✔
1775
            logerr(gl_LOGFILE, "--allow-signing requires --tpm2.\n");
×
1776
            goto error;
×
1777
        }
1778
        if (flags & SETUP_DECRYPTION_F) {
29✔
1779
            logerr(gl_LOGFILE, "--decryption requires --tpm2.\n");
×
1780
            goto error;
×
1781
        }
1782
        if (pcr_banks) {
29✔
1783
            logerr(gl_LOGFILE, "--pcr-banks requires --tpm2.\n");
×
1784
            goto error;
×
1785
        }
1786
    }
1787

1788
    if (!(flags & SETUP_RECONFIGURE_F)) {
157✔
1789
        ret = check_state_overwrite((const char **)swtpm_prg_l, flags, tpm_state_path);
151✔
1790
        if (ret == 1) {
151✔
1791
            goto error;
3✔
1792
        } else if (ret == 2) {
148✔
1793
            ret = 0;
2✔
1794
            goto out;
2✔
1795
        }
1796

1797
        ret = backend_ops->delete_state(backend_state);
146✔
1798
        if (ret != 0)
146✔
1799
            goto error;
×
1800
    }
1801

1802
    if (!config_file_lines &&
304✔
1803
        read_config_file(config_file, curr_user, &config_file_lines) < 0)
152✔
1804
        goto error;
×
1805

1806
    /* check pcr_banks; read from config file if not given */
1807
    tmp_l = g_strsplit(pcr_banks ? pcr_banks : "", ",", -1);
152✔
1808
    for (i = 0, n = 0; tmp_l[i]; i++) {
318✔
1809
        g_strstrip(tmp_l[i]);
14✔
1810
        n += strlen(tmp_l[i]);
14✔
1811
    }
1812
    g_strfreev(tmp_l);
152✔
1813
    if (n == 0) {
152✔
1814
        g_free(pcr_banks);
144✔
1815
        pcr_banks = get_default_pcr_banks(config_file_lines);
144✔
1816
    }
1817

1818
    if ((json_profile != NULL) +
152✔
1819
        (json_profile_name != NULL) +
152✔
1820
        (json_profile_file != NULL) +
152✔
1821
        (json_profile_fd > 0) > 1) {
152✔
1822
        logerr(gl_LOGFILE, "Only one of --profile, --profile-name, --profile-file, and --profile-file-fd may be given.\n");
×
1823
        goto error;
×
1824
    }
1825

1826
    if ((flags & SETUP_RECONFIGURE_F) &&
152✔
1827
         (json_profile ||
6✔
1828
          json_profile_name ||
6✔
1829
          json_profile_file ||
6✔
1830
          json_profile_fd > 0)) {
1831
            logerr(gl_LOGFILE, "Reconfiguration does not accept a (new) profile.\n");
×
1832
            goto error;
×
1833
    }
1834

1835
    if (json_profile_name) {
152✔
1836
        if (profile_name_check(json_profile_name) < 0)
16✔
1837
            goto error;
×
1838
        /*
1839
         * Load profile from distro and local locations; sets json_profile_file
1840
         * to filename or json_profile with the JSON.
1841
         */
1842
        if (profile_get_by_name(config_file_lines,
16✔
1843
                                json_profile_name,
1844
                                &json_profile_file,
1845
                                &json_profile) < 0) {
1846
            logerr(gl_LOGFILE, "Could not find or access profile '%s'.\n",
×
1847
                   json_profile_name);
1848
            goto error;
×
1849
        }
1850
    }
1851

1852
    if (json_profile_file) {
152✔
1853
        json_profile_fd = open(json_profile_file, O_RDONLY);
5✔
1854
        if (json_profile_fd < 0) {
5✔
1855
            logerr(gl_LOGFILE, "Could not open profile file '%s': %s\n",
×
1856
                   json_profile_file, strerror(errno));
×
1857
            goto error;
×
1858
        }
1859
    }
1860

1861
    /*
1862
     * Read default profile from swtpm_setup.conf;
1863
     * Do not read it when --reconfigure'ing
1864
     */
1865
    if ((flags & SETUP_TPM2_F) != 0 &&
152✔
1866
        json_profile == NULL && json_profile_fd < 0 &&
126✔
1867
        (flags & SETUP_RECONFIGURE_F) == 0) {
1868

1869
        json_profile_fd = get_default_profile_fd(config_file_lines);
43✔
1870
        if (json_profile_fd == -2)
43✔
1871
            goto error;
×
1872
        if (json_profile_fd < 0)
43✔
1873
            json_profile = get_default_profile(config_file_lines);
43✔
1874
    }
1875

1876
    if (json_profile_fd >= 0)
152✔
1877
        fds_to_pass[n_fds_to_pass++] = json_profile_fd;
5✔
1878

1879
    if ((flags & SETUP_TPM2_F) != 0 && json_profile) {
152✔
1880
        if (validate_json_profile((const char **)swtpm_prg_l, json_profile) != 0)
85✔
1881
            goto error;
1✔
1882
    } else if (json_profile) {
67✔
1883
        logerr(gl_LOGFILE, "There's no --profile support for TPM 1.2\n");
×
1884
        goto error;
×
1885
    }
1886

1887
    if (cipher != NULL) {
151✔
1888
        if (strcmp(cipher, "aes-128-cbc") != 0 &&
151✔
1889
            strcmp(cipher, "aes-cbc") != 0 &&
13✔
1890
            strcmp(cipher, "aes-256-cbc") != 0) {
13✔
1891
            logerr(gl_LOGFILE, "Unsupported cipher %s.\n", cipher);
×
1892
            goto error;
×
1893
        }
1894
        tmp = g_strdup_printf(",mode=%s", cipher);
151✔
1895
        g_free(cipher);
151✔
1896
        cipher = tmp;
151✔
1897
    }
1898

1899
    if (keyfile != NULL) {
151✔
1900
        if (access(keyfile, R_OK) != 0) {
12✔
1901
            logerr(gl_LOGFILE, "User %s cannot read keyfile %s.\n",
×
1902
                   curr_user ? curr_user->pw_name : "<unknown>", keyfile);
1903
            goto error;
×
1904
        }
1905
        swtpm_keyopt = g_strdup_printf("file=%s%s", keyfile, cipher);
12✔
1906
        logit(gl_LOGFILE, "  The TPM's state will be encrypted with a provided key.\n");
12✔
1907
    } else if (pwdfile != NULL) {
139✔
1908
        if (access(pwdfile, R_OK) != 0) {
17✔
1909
            logerr(gl_LOGFILE, "User %s cannot read passphrase file %s.\n",
×
1910
                   curr_user ? curr_user->pw_name : "<unknown>", pwdfile);
1911
            goto error;
×
1912
        }
1913
        swtpm_keyopt = g_strdup_printf("pwdfile=%s%s", pwdfile, cipher);
17✔
1914
        logit(gl_LOGFILE, "  The TPM's state will be encrypted using a key derived from a passphrase.\n");
17✔
1915
    } else if (keyfile_fd >= 0) {
122✔
1916
        fds_to_pass[n_fds_to_pass++] = keyfile_fd;
2✔
1917
        swtpm_keyopt = g_strdup_printf("fd=%ld%s", keyfile_fd, cipher);
2✔
1918
        logit(gl_LOGFILE, "  The TPM's state will be encrypted with a provided key (fd).\n");
2✔
1919
    } else if (pwdfile_fd >= 0) {
120✔
1920
        fds_to_pass[n_fds_to_pass++] = pwdfile_fd;
2✔
1921
        swtpm_keyopt = g_strdup_printf("pwdfd=%ld%s", pwdfile_fd, cipher);
2✔
1922
        logit(gl_LOGFILE, "  The TPM's state will be encrypted using a key derived from a passphrase (fd).\n");
2✔
1923
    }
1924

1925
    if ((flags & SETUP_RSA_KEYSIZE_BY_USER_F) == 0)
151✔
1926
        rsa_keysize_str = get_default_rsa_keysize(config_file_lines);
131✔
1927

1928
    if (strcmp(rsa_keysize_str, "max") == 0) {
151✔
1929
        unsigned int *keysizes = NULL;
×
1930
        size_t n_keysizes;
×
1931

1932
        ret = get_rsa_keysizes(flags, (const char **)swtpm_prg_l, &keysizes, &n_keysizes);
×
1933
        if (ret)
×
1934
            goto error;
×
1935
        g_free(rsa_keysize_str);
×
1936
        if (n_keysizes > 0) {
×
1937
            /* last one is the biggest one */
1938
            rsa_keysize_str = g_strdup_printf("%u", keysizes[n_keysizes - 1]);
×
1939
        } else {
1940
            rsa_keysize_str = g_strdup("2048");
×
1941
        }
1942
        g_free(keysizes);
×
1943
    }
1944
    if (strcmp(rsa_keysize_str, "2048") == 0 ||
151✔
1945
        strcmp(rsa_keysize_str, "3072") == 0 ||
19✔
1946
        strcmp(rsa_keysize_str, "4096") == 0) {
7✔
1947
        unsigned int *keysizes = NULL;
151✔
1948
        size_t n_keysizes;
151✔
1949
        gboolean found = FALSE;
151✔
1950

1951
        ret = get_rsa_keysizes(flags, (const char **)swtpm_prg_l, &keysizes, &n_keysizes);
151✔
1952
        if (ret)
151✔
1953
            goto error;
×
1954

1955
        rsa_keysize = strtoull(rsa_keysize_str, NULL, 10);
151✔
1956
        for (i = 0; i < n_keysizes && found == FALSE; i++)
427✔
1957
            found = (keysizes[i] == rsa_keysize);
276✔
1958
        if (!found && rsa_keysize != 2048) {
151✔
1959
            logerr(gl_LOGFILE, "%u bit RSA keys are not supported by libtpms.\n", rsa_keysize);
×
1960
            goto error;
×
1961
        }
1962
        g_free(keysizes);
151✔
1963
    } else {
1964
        logit(gl_LOGFILE, "Unsupported RSA key size %s.\n", rsa_keysize_str);
×
1965
        goto error;
×
1966
    }
1967

1968
    if (flags & SETUP_RECONFIGURE_F) {
151✔
1969
        if (flags & (SETUP_CREATE_EK_F | SETUP_EK_CERT_F | SETUP_PLATFORM_CERT_F)) {
6✔
1970
            logerr(gl_LOGFILE, "Reconfiguration is not supported with creation of EK or certificates\n");
×
1971
            goto error;
×
1972
        }
1973
    }
1974

1975
    now = time(NULL);
151✔
1976
    tm = localtime(&now);
151✔
1977
    if (strftime(tmpbuffer, sizeof(tmpbuffer), "%a %d %h %Y %I:%M:%S %p %Z", tm) == 0) {
151✔
1978
        logerr(gl_LOGFILE, "Could not format time/date string.\n");
×
1979
        goto error;
×
1980
    }
1981
    curr_grp = getgrgid(getgid());
151✔
1982
    logit(gl_LOGFILE, "Starting vTPM %s as %s:%s @ %s\n",
296✔
1983
          flags & SETUP_RECONFIGURE_F ? "reconfiguration" : "manufacturing",
1984
          curr_user ? curr_user->pw_name : "<unknown>",
1985
          curr_grp ? curr_grp->gr_name : "<unknown>",
1986
          tmpbuffer);
1987

1988
    if (flags & (SETUP_EK_CERT_F | SETUP_PLATFORM_CERT_F)) {
151✔
1989
        certsdir = g_dir_make_tmp("swtpm_setup.certs.XXXXXX", &error);
47✔
1990
        if (certsdir == NULL) {
47✔
1991
            logerr(gl_LOGFILE, "Could not create temporary directory for certs: %s\n",
×
1992
                   error->message);
×
1993
            goto error;
×
1994
        }
1995
    }
1996

1997
    if ((flags & SETUP_TPM2_F) == 0) {
151✔
1998
        ret = init_tpm(flags, swtpm_prg_l, config_file, tpm_state_path, ownerpass, srkpass, vmid,
26✔
1999
                       swtpm_keyopt, fds_to_pass, n_fds_to_pass, certsdir, user_certsdir);
2000
    } else {
2001
        ret = init_tpm2(flags, swtpm_prg_l, config_file, tpm_state_path, vmid, pcr_banks,
125✔
2002
                       swtpm_keyopt, fds_to_pass, n_fds_to_pass, rsa_keysize, certsdir,
2003
                       user_certsdir, json_profile, json_profile_fd,
2004
                       profile_remove_disabled_param);
2005
    }
2006

2007
    if (ret == 0) {
151✔
2008
        logit(gl_LOGFILE, "Successfully authored TPM state.\n");
143✔
2009
    } else {
2010
        logerr(gl_LOGFILE, "An error occurred. Authoring the TPM state failed.\n");
8✔
2011
        backend_ops->delete_state(backend_state);
8✔
2012
    }
2013

2014
    now = time(NULL);
151✔
2015
    tm = localtime(&now);
151✔
2016
    if (strftime(tmpbuffer, sizeof(tmpbuffer), "%a %d %h %Y %I:%M:%S %p %Z", tm) == 0) {
151✔
2017
        logerr(gl_LOGFILE, "Could not format time/date string.\n");
×
2018
        goto error;
×
2019
    }
2020
    logit(gl_LOGFILE, "Ending vTPM manufacturing @ %s\n",
151✔
2021
          tmpbuffer);
2022

2023
out:
182✔
2024
    if (certsdir && g_rmdir(certsdir) != 0)
182✔
2025
        logerr(gl_LOGFILE, "Could not remove temporary directory for certs: %s\n",
×
2026
               strerror(errno));
×
2027

2028
    if (backend_ops && backend_state)
182✔
2029
        backend_ops->free_backend(backend_state);
157✔
2030
    g_strfreev(swtpm_prg_l);
182✔
2031
    g_free(gl_LOGFILE);
182✔
2032

2033
    return ret;
182✔
2034

2035
error:
15✔
2036
    ret = 1;
15✔
2037
    goto out;
15✔
2038
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc