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

stefanberger / swtpm / #2863

18 Aug 2025 06:28PM UTC coverage: 72.855% (-0.06%) from 72.913%
#2863

push

travis-ci

web-flow
Merge f42746acb into 3d5d0f2fc

7496 of 10289 relevant lines covered (72.85%)

10411.15 hits per line

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

78.12
/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
        if (gl_LOGFILE != NULL)
86✔
234
            cmd = concat_arrays(cmd, (const gchar*[]){"--logfile", gl_LOGFILE, NULL}, TRUE);
11✔
235
        if (vmid != NULL)
86✔
236
            cmd = concat_arrays(cmd, (const gchar*[]){"--vmid", vmid, NULL}, TRUE);
75✔
237
        cmd = concat_arrays(cmd, (const char **)params, TRUE);
86✔
238
        if (create_certs_tool_config != NULL)
86✔
239
            cmd = concat_arrays(cmd, (const gchar*[]){"--configfile", create_certs_tool_config, NULL}, TRUE);
11✔
240
        if (create_certs_tool_options != NULL)
86✔
241
            cmd = concat_arrays(cmd, (const gchar*[]){"--optsfile", create_certs_tool_options, NULL}, TRUE);
11✔
242

243
        s = g_strrstr(create_certs_tool, G_DIR_SEPARATOR_S);
86✔
244
        if (s)
86✔
245
            prgname = strdup(&s[1]);
11✔
246
        else
247
            prgname = strdup(create_certs_tool);
75✔
248

249
        for (idx = 0; flags_to_certfiles[idx].filename != NULL; idx++) {
258✔
250
            if (cert_flags & flags_to_certfiles[idx].flag) {
172✔
251
                g_autofree gchar *standard_output = NULL;
132✔
252
                g_autofree gchar *standard_error = NULL;
132✔
253
                GError *error = NULL;
132✔
254
                gchar **lines;
132✔
255

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

258
                s = g_strjoinv(" ", (char **)cmd);
132✔
259
                logit(gl_LOGFILE, "  Invoking %s\n", s);
132✔
260
                g_free(s);
132✔
261

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

277
                lines = g_strsplit(standard_output, "\n", -1);
132✔
278
                for (j = 0; lines[j] != NULL; j++) {
264✔
279
                    if (strlen(lines[j]) > 0)
×
280
                        logit(gl_LOGFILE, "%s: %s\n", prgname, lines[j]);
×
281
                }
282
                g_strfreev(lines);
132✔
283

284
                SWTPM_G_FREE(standard_output);
132✔
285
                SWTPM_G_FREE(standard_error);
132✔
286
            }
287
        }
288
    }
289

290
error:
×
291
    g_strfreev(config_file_lines);
86✔
292
    g_strfreev(params);
86✔
293

294
    return ret;
86✔
295
}
296

297
static char *create_certfile_name(const gchar *user_certsdir,
11✔
298
                                  const gchar *key_type,
299
                                  const gchar *key_description)
300
{
301
    g_autofree gchar *filename = g_strdup_printf("%s-%s.crt", key_type, key_description);
11✔
302

303
    return g_strjoin(G_DIR_SEPARATOR_S, user_certsdir, filename, NULL);
11✔
304
}
305

306
/*
307
 * Remove the cert file unless the user wants a copy of it.
308
 */
309
static int certfile_move_or_delete(unsigned long flags, gboolean preserve, const gchar *certfile,
132✔
310
                                   const gchar *user_certsdir, const gchar *key_type,
311
                                   const gchar *key_description)
312
{
313
    g_autofree gchar *content = NULL;
264✔
314
    g_autofree gchar *cf = NULL;
132✔
315
    gsize content_length;
132✔
316
    GError *error = NULL;
132✔
317
    size_t offset = 0;
132✔
318

319
    if (preserve && (flags & SETUP_WRITE_EK_CERT_FILES_F) && user_certsdir != NULL) {
132✔
320
        if (!g_file_get_contents(certfile, &content, &content_length, &error))
11✔
321
            goto error;
×
322

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

340
    return 0;
132✔
341

342
error:
×
343
    logerr(gl_LOGFILE, "%s\n", error->message);
×
344
    g_error_free(error);
×
345

346
error_unlink:
×
347
    unlink(certfile);
×
348

349
    return 1;
×
350
}
351

352
static int read_certificate_file(const gchar *certsdir, const gchar *filename,
132✔
353
                                 gchar **filecontent, size_t *filecontent_len,
354
                                 gchar **certfile)
355
{
356
    *certfile = g_strjoin(G_DIR_SEPARATOR_S, certsdir, filename, NULL);
132✔
357

358
    return read_file(*certfile, filecontent, filecontent_len);
132✔
359
}
360

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

377
    ret = read_certificate_file(certsdir, ftc->filename,
117✔
378
                                &filecontent, &filecontent_len, &certfile);
379
    if (ret != 0)
117✔
380
        goto error_unlink;
×
381

382
    if (ftc->flag == SETUP_EK_CERT_F) {
117✔
383
        ret = swtpm2->ops->write_ek_cert_nvram(&swtpm2->swtpm,
78✔
384
                                     !!(flags & SETUP_TPM2_ECC_F), rsa_keysize,
78✔
385
                                     !!(flags & SETUP_LOCK_NVRAM_F),
78✔
386
                                     (const unsigned char*)filecontent, filecontent_len);
387
    } else {
388
        ret = swtpm2->ops->write_platform_cert_nvram(&swtpm2->swtpm,
39✔
389
                                     !!(flags & SETUP_LOCK_NVRAM_F),
39✔
390
                                     (const unsigned char *)filecontent, filecontent_len);
391
    }
392

393
    if (ret != 0)
117✔
394
        goto error_unlink;
×
395

396
    return certfile_move_or_delete(flags, !!(ftc->flag & SETUP_EK_CERT_F),
117✔
397
                                   certfile, user_certsdir,
398
                                   key_type, key_description);
399

400
error_unlink:
×
401
    unlink(certfile);
×
402
    return 1;
×
403
}
404

405
/* Create EK and certificate for a TPM 2 */
406
static int tpm2_create_ek_and_cert(unsigned long flags, const gchar *config_file,
224✔
407
                                   const gchar *certsdir, const gchar *vmid,
408
                                   unsigned int rsa_keysize, struct swtpm2 *swtpm2,
409
                                   const gchar *user_certsdir)
410
{
411
    const char *key_description = "";
224✔
412
    g_autofree gchar *ekparam = NULL;
448✔
413
    unsigned long cert_flags;
224✔
414
    const gchar *key_type;
224✔
415
    size_t idx;
224✔
416
    int ret;
224✔
417

418
    if (flags & SETUP_CREATE_EK_F) {
224✔
419
        ret = swtpm2->ops->create_ek(&swtpm2->swtpm, !!(flags & SETUP_TPM2_ECC_F), rsa_keysize,
184✔
420
                                     !!(flags & SETUP_ALLOW_SIGNING_F),
92✔
421
                                     !!(flags & SETUP_DECRYPTION_F),
92✔
422
                                     !!(flags & SETUP_LOCK_NVRAM_F),
92✔
423
                                     &ekparam, &key_description);
424
        if (ret != 0)
92✔
425
            return 1;
426
    }
427

428
    /* Only look at ek and platform certs here */
429
    cert_flags = flags & (SETUP_EK_CERT_F | SETUP_PLATFORM_CERT_F);
224✔
430
    if (cert_flags) {
224✔
431
        ret = call_create_certs(flags, cert_flags, config_file, certsdir, ekparam,
78✔
432
                                vmid, &swtpm2->swtpm);
433
        if (ret != 0)
78✔
434
            return 1;
435

436
        for (idx = 0; flags_to_certfiles[idx].filename; idx++) {
234✔
437
            if (cert_flags & flags_to_certfiles[idx].flag) {
156✔
438
                key_type = flags_to_certfiles[idx].flag & SETUP_EK_CERT_F ? "ek" : "";
117✔
439

440
                ret = tpm2_persist_certificate(flags, certsdir, &flags_to_certfiles[idx],
117✔
441
                                               rsa_keysize, swtpm2, user_certsdir,
442
                                               key_type, key_description);
443
                if (ret)
117✔
444
                    return 1;
445
            }
446
        }
447
    }
448

449
    return 0;
450
}
451

452
/* Create endorsement keys and certificates for a TPM 2 */
453
static int tpm2_create_eks_and_certs(unsigned long flags, const gchar *config_file,
112✔
454
                                     const gchar *certsdir, const gchar *vmid,
455
                                     unsigned int rsa_keysize, struct swtpm2 *swtpm2,
456
                                     const gchar *user_certsdir)
457
{
458
     int ret;
112✔
459

460
     /* 1st key will be RSA */
461
     flags = flags & ~SETUP_TPM2_ECC_F;
112✔
462
     ret = tpm2_create_ek_and_cert(flags, config_file, certsdir, vmid, rsa_keysize, swtpm2,
112✔
463
                                   user_certsdir);
464
     if (ret != 0)
112✔
465
         return 1;
466

467
     /* 2nd key will be an ECC; no more platform cert */
468
     flags = (flags & ~SETUP_PLATFORM_CERT_F) | SETUP_TPM2_ECC_F;
112✔
469
     return tpm2_create_ek_and_cert(flags, config_file, certsdir, vmid, rsa_keysize, swtpm2,
112✔
470
                                    user_certsdir);
471
}
472

473
/* Get the default PCR banks from the config file and if nothing can
474
   be found there use the DEFAULT_PCR_BANKS #define.
475
 */
476
static gchar *get_default_pcr_banks(gchar *const *config_file_lines)
144✔
477
{
478
    gchar *pcr_banks;
144✔
479

480
    pcr_banks = get_config_value(config_file_lines, "active_pcr_banks");
144✔
481
    if (pcr_banks)
144✔
482
        g_strstrip(pcr_banks);
27✔
483
    if (pcr_banks == NULL || strlen(pcr_banks) == 0) {
144✔
484
        g_free(pcr_banks);
117✔
485
        pcr_banks = g_strdup(DEFAULT_PCR_BANKS);
117✔
486
    }
487
    return pcr_banks;
144✔
488
}
489

490
/* Get the default RSA keysize from the config file */
491
static gchar *get_default_rsa_keysize(gchar *const *config_file_lines)
131✔
492
{
493
    gchar *rsa_keysize;
131✔
494

495
    rsa_keysize = get_config_value(config_file_lines, "rsa_keysize");
131✔
496
    if (rsa_keysize)
131✔
497
        g_strstrip(rsa_keysize);
24✔
498
    if (rsa_keysize == NULL || strlen(rsa_keysize) == 0) {
131✔
499
        g_free(rsa_keysize);
107✔
500
        rsa_keysize = g_strdup_printf("%d", DEFAULT_RSA_KEYSIZE);
107✔
501
    }
502
    return rsa_keysize;
131✔
503
}
504

505
/* Get the default profile from the config file */
506
static gchar *get_default_profile(gchar *const *config_file_lines)
43✔
507
{
508
    gchar *profile;
43✔
509

510
    profile = get_config_value(config_file_lines, "profile");
43✔
511
    if (profile)
43✔
512
        g_strstrip(profile);
13✔
513
    return profile;
43✔
514
}
515

516
/* If available, open the default profile and return its file descriptor */
517
static int get_default_profile_fd(gchar *const *config_file_lines)
43✔
518
{
519
    g_autofree gchar *profile_file = NULL;
86✔
520
    int fd;
43✔
521

522
    profile_file = get_config_value(config_file_lines, "profile_file");
43✔
523
    if (!profile_file)
43✔
524
        return -1;
525

526
    fd = open(profile_file, O_RDONLY);
×
527
    if (fd < 0) {
×
528
        logerr(gl_LOGFILE, "Could not read default profile '%s': %s",
×
529
               profile_file, strerror(errno));
×
530
        return -2;
×
531
    }
532
    return fd;
533
}
534

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

549
    if (g_str_equal(pcr_banks, "-"))
118✔
550
        return 0;
551

552
    ret = swtpm2->ops->get_all_pcr_banks(swtpm, &all_pcr_banks);
118✔
553
    if (ret != 0)
118✔
554
        return ret;
555

556
    pcr_banks_l = g_strsplit(pcr_banks, ",", -1);
118✔
557
    ret = swtpm2->ops->set_active_pcr_banks(swtpm, pcr_banks_l, all_pcr_banks,
118✔
558
                                            &active_pcr_banks);
559
    if (ret != 0)
118✔
560
        return ret;
561

562
    active_pcr_banks_join = g_strjoinv(",", active_pcr_banks);
117✔
563
    all_pcr_banks_join = g_strjoinv(",", all_pcr_banks);
117✔
564
    logit(gl_LOGFILE, "Successfully activated PCR banks %s among %s.\n",
117✔
565
          active_pcr_banks_join, all_pcr_banks_join);
566

567
    return 0;
117✔
568
}
569

570
static int log_active_profile(struct swtpm2 *swtpm2)
119✔
571
{
572
    g_autofree gchar *profile = NULL;
238✔
573
    char *tmp;
119✔
574

575
    profile = swtpm2->ops->get_active_profile(&swtpm2->swtpm);
119✔
576
    if (!profile) {
119✔
577
        logerr(gl_LOGFILE, "Could not get active profile.\n");
7✔
578
        return 1;
7✔
579
    }
580
    /* Strip out surrounding '{"ActiveProfile":<to display>} */
581
    tmp = strrchr(profile, '}');
112✔
582
    if (!tmp)
112✔
583
        goto malformatted;
×
584
    *tmp = 0;
112✔
585

586
    tmp = strchr(profile, ':');
112✔
587
    if (!tmp)
112✔
588
        goto malformatted;
×
589

590
    logit(gl_LOGFILE, "Active profile: %s\n", tmp + 1);
112✔
591
    return 0;
112✔
592

593
malformatted:
×
594
    logerr(gl_LOGFILE, "Malformatted active profile");
×
595
    return 1;
×
596
}
597

598
/* Simulate manufacturing a TPM 2: create keys and certificates */
599
static int init_tpm2(unsigned long flags, gchar **swtpm_prg_l, const gchar *config_file,
125✔
600
                     const gchar *tpm2_state_path, const gchar *vmid, const gchar *pcr_banks,
601
                     const gchar *swtpm_keyopt, int *fds_to_pass, size_t n_fds_to_pass,
602
                     unsigned int rsa_keysize, const gchar *certsdir,
603
                     const gchar *user_certsdir, const gchar *json_profile,
604
                     int json_profile_fd, const gchar *profile_remove_disabled_param)
605
{
606
    struct swtpm2 *swtpm2;
125✔
607
    struct swtpm *swtpm;
125✔
608
    int ret;
125✔
609

610
    swtpm2 = swtpm2_new(swtpm_prg_l, tpm2_state_path, swtpm_keyopt, gl_LOGFILE,
125✔
611
                        fds_to_pass, n_fds_to_pass, json_profile, json_profile_fd,
612
                        profile_remove_disabled_param);
613
    if (swtpm2 == NULL)
125✔
614
        return 1;
615
    swtpm = &swtpm2->swtpm;
125✔
616

617
    ret = swtpm->cops->start(swtpm);
125✔
618
    if (ret != 0) {
125✔
619
        logerr(gl_LOGFILE, "Could not start the TPM 2.\n");
×
620
        goto error;
×
621
    }
622

623
    if (!(flags & SETUP_RECONFIGURE_F)) {
125✔
624
        ret = log_active_profile(swtpm2);
119✔
625
        if (ret)
119✔
626
            goto error;
7✔
627

628
        if ((flags & SETUP_CREATE_SPK_F)) {
112✔
629
            ret = swtpm2->ops->create_spk(swtpm, !!(flags & SETUP_TPM2_ECC_F), rsa_keysize);
4✔
630
            if (ret != 0)
4✔
631
                goto destroy;
×
632
        }
633

634
        ret = tpm2_create_eks_and_certs(flags, config_file, certsdir, vmid, rsa_keysize, swtpm2,
112✔
635
                                        user_certsdir);
636
        if (ret != 0)
112✔
637
            goto destroy;
×
638
    }
639

640
    ret = tpm2_activate_pcr_banks(swtpm2, pcr_banks);
118✔
641
    if (ret != 0)
118✔
642
        goto destroy;
1✔
643

644
    ret = swtpm2->ops->shutdown(swtpm);
117✔
645

646
destroy:
118✔
647
    swtpm->cops->destroy(swtpm);
118✔
648

649
error:
125✔
650
    swtpm_free(swtpm);
125✔
651

652
    return ret;
125✔
653
}
654

655
/* Create the owner password digest */
656
static void tpm12_get_ownerpass_digest(unsigned long flags, const gchar *ownerpass,
9✔
657
                                       unsigned char ownerpass_digest[SHA_DIGEST_LENGTH])
658
{
659
    const gchar zeros[SHA_DIGEST_LENGTH]= {0, };
9✔
660
    size_t len;
9✔
661

662
    if (ownerpass == NULL) {
9✔
663
        if (flags & SETUP_OWNERPASS_ZEROS_F) {
2✔
664
            ownerpass = zeros;
665
            len = sizeof(zeros);
666
        } else {
667
            ownerpass = DEFAULT_OWNER_PASSWORD;
×
668
            len = strlen(ownerpass);
×
669
        }
670
    } else {
671
        len = strlen(ownerpass);
7✔
672
    }
673
    SHA1((const unsigned char *)ownerpass, len, ownerpass_digest);
9✔
674
}
9✔
675

676
/* Create the SRK password digest */
677
static void tpm12_get_srkpass_digest(unsigned long flags, const gchar *srkpass,
9✔
678
                                     unsigned char srkpass_digest[SHA_DIGEST_LENGTH])
679
{
680
    const gchar zeros[SHA_DIGEST_LENGTH]= {0, };
9✔
681
    size_t len;
9✔
682

683
    if (srkpass == NULL) {
9✔
684
        if (flags & SETUP_SRKPASS_ZEROS_F) {
2✔
685
            srkpass = zeros;
686
            len = sizeof(zeros);
687
        } else {
688
            srkpass = DEFAULT_SRK_PASSWORD;
×
689
            len = strlen(srkpass);
×
690
        }
691
    } else {
692
        len = strlen(srkpass);
7✔
693
    }
694
    SHA1((const unsigned char *)srkpass, len, srkpass_digest);
9✔
695
}
9✔
696

697
/* Take ownership of a TPM 1.2 */
698
static int tpm12_take_ownership(unsigned long flags, const gchar *ownerpass,
9✔
699
                                const gchar *srkpass, gchar *pubek, size_t pubek_len,
700
                                struct swtpm12 *swtpm12)
701
{
702
    unsigned char ownerpass_digest[SHA_DIGEST_LENGTH];
9✔
703
    unsigned char srkpass_digest[SHA_DIGEST_LENGTH];
9✔
704

705
    tpm12_get_ownerpass_digest(flags, ownerpass, ownerpass_digest);
9✔
706
    tpm12_get_srkpass_digest(flags, srkpass, srkpass_digest);
9✔
707

708
    return swtpm12->ops->take_ownership(&swtpm12->swtpm, ownerpass_digest, srkpass_digest,
9✔
709
                                        (const unsigned char *)pubek, pubek_len);
710
}
711

712
/* Create the certificates for a TPM 1.2 */
713
static int tpm12_create_certs(unsigned long flags, const gchar *config_file,
8✔
714
                              const gchar *certsdir, const gchar *ekparam,
715
                              const gchar *vmid, struct swtpm12 *swtpm12,
716
                              const gchar *user_certsdir)
717
{
718
    g_autofree gchar *filecontent = NULL;
16✔
719
    g_autofree gchar *certfile = NULL;
8✔
720
    unsigned int cert_flags;
8✔
721
    const gchar *key_type;
8✔
722
    gsize filecontent_len;
8✔
723
    size_t idx;
8✔
724
    int ret;
8✔
725

726
    /* TPM 1.2 only has ek and platform certs */
727
    cert_flags = flags & (SETUP_EK_CERT_F | SETUP_PLATFORM_CERT_F);
8✔
728

729
    ret = call_create_certs(flags, cert_flags, config_file, certsdir, ekparam,
8✔
730
                            vmid, &swtpm12->swtpm);
731
    if (ret != 0)
8✔
732
        return 1;
733

734
    for (idx = 0; flags_to_certfiles[idx].filename; idx++) {
24✔
735
        if (cert_flags & flags_to_certfiles[idx].flag) {
16✔
736
            SWTPM_G_FREE(filecontent);
15✔
737
            SWTPM_G_FREE(certfile);
15✔
738

739
            ret = read_certificate_file(certsdir, flags_to_certfiles[idx].filename,
15✔
740
                                        &filecontent, &filecontent_len, &certfile);
741
            if (ret != 0)
15✔
742
                return 1;
743

744
            if (flags_to_certfiles[idx].flag == SETUP_EK_CERT_F) {
15✔
745
                ret = swtpm12->ops->write_ek_cert_nvram(&swtpm12->swtpm,
8✔
746
                                                (const unsigned char*)filecontent, filecontent_len);
747
                if (ret == 0)
8✔
748
                    logit(gl_LOGFILE, "Successfully created NVRAM area for EK certificate.\n");
8✔
749
            } else {
750
                ret = swtpm12->ops->write_platform_cert_nvram(&swtpm12->swtpm,
7✔
751
                                                  (const unsigned char*)filecontent, filecontent_len);
752
                if (ret == 0)
7✔
753
                    logit(gl_LOGFILE, "Successfully created NVRAM area for Platform certificate.\n");
7✔
754
            }
755

756
            if (ret != 0) {
15✔
757
                unlink(certfile);
×
758
                return 1;
×
759
            }
760

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

763
            if (certfile_move_or_delete(flags, !!(flags_to_certfiles[idx].flag & SETUP_EK_CERT_F),
15✔
764
                                        certfile, user_certsdir, key_type, "rsa2048") != 0)
765
                return 1;
766
        }
767
    }
768

769
    return 0;
770
}
771

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

785
    swtpm12 = swtpm12_new(swtpm_prg_l, tpm_state_path, swtpm_keyopt, gl_LOGFILE,
26✔
786
                          fds_to_pass, n_fds_to_pass);
787
    if (swtpm12 == NULL)
26✔
788
        return 1;
789
    swtpm = &swtpm12->swtpm;
26✔
790

791
    ret = swtpm->cops->start(swtpm);
26✔
792
    if (ret != 0) {
26✔
793
        logerr(gl_LOGFILE, "Could not start the TPM 1.2.\n");
×
794
        goto error;
×
795
    }
796

797
    ret = swtpm12->ops->run_swtpm_bios(swtpm);
26✔
798
    if (ret != 0)
26✔
799
         goto destroy;
×
800

801
    if ((flags & SETUP_CREATE_EK_F)) {
26✔
802
        ret = swtpm12->ops->create_endorsement_key_pair(swtpm, &pubek, &pubek_len);
19✔
803
        if (ret != 0)
19✔
804
            goto destroy;
×
805

806
        logit(gl_LOGFILE, "Successfully created EK.\n");
19✔
807

808
        /* can only take owernship if created an EK */
809
        if ((flags & SETUP_TAKEOWN_F)) {
19✔
810
            ret = tpm12_take_ownership(flags, ownerpass, srkpass, pubek, pubek_len, swtpm12);
9✔
811
            if (ret != 0)
9✔
812
                goto destroy;
×
813

814
            logit(gl_LOGFILE, "Successfully took ownership of the TPM.\n");
9✔
815
        }
816

817
        /* can only create EK cert if created an EK */
818
        if ((flags & SETUP_EK_CERT_F)) {
19✔
819
            g_autofree gchar *ekparam = print_as_hex((unsigned char *)pubek, pubek_len);
16✔
820

821
            ret = tpm12_create_certs(flags, config_file, certsdir, ekparam, vmid, swtpm12,
8✔
822
                                     user_certsdir);
823
            if (ret != 0)
8✔
824
                goto destroy;
×
825
        }
826
    }
827

828
    if ((flags & SETUP_LOCK_NVRAM_F)) {
26✔
829
        ret = swtpm12->ops->nv_lock(swtpm);
12✔
830
        if (ret == 0)
12✔
831
            logit(gl_LOGFILE, "Successfully locked NVRAM access.\n");
12✔
832
    }
833

834
destroy:
14✔
835
    swtpm->cops->destroy(swtpm);
26✔
836

837
error:
26✔
838
    swtpm_free(swtpm);
26✔
839

840
    return ret;
26✔
841
}
842

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

859
    my_argv = concat_arrays((const gchar*[]) {
151✔
860
                                "--print-states",
861
                                "--tpmstate",
862
                                statearg,
863
                                NULL
864
                            }, NULL, FALSE);
865

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

869
    if (gl_LOGFILE != NULL) {
151✔
870
        logop = g_strdup_printf("file=%s", gl_LOGFILE);
87✔
871
        my_argv = concat_arrays(my_argv, (const gchar*[]){"--log", logop, NULL}, TRUE);
87✔
872
    }
873

874
    argv = concat_arrays(swtpm_prg_l, my_argv, FALSE);
151✔
875

876
    success = spawn_sync(NULL, argv, NULL, G_SPAWN_STDERR_TO_DEV_NULL, NULL, NULL,
151✔
877
                         &standard_output, NULL, &exit_status, &error);
878
    if (!success) {
151✔
879
        logerr(gl_LOGFILE, "Could not start swtpm '%s': %s\n", swtpm_prg_l[0], error->message);
×
880
        return 1;
×
881
    }
882

883
    if (exit_status != 0) {
151✔
884
        logerr(gl_LOGFILE, "%s exit with status %d: %s\n",
×
885
               swtpm_prg_l[0], exit_status, standard_output);
886
        return 1;
×
887
    }
888

889
    if (g_strstr_len(standard_output, -1, TPM_PERMANENT_ALL_NAME) != NULL) {
151✔
890
        /* State file exists */
891
        if (flags & SETUP_STATE_NOT_OVERWRITE_F) {
75✔
892
            logit(gl_LOGFILE, "Not overwriting existing state file.\n");
2✔
893
            return 2;
2✔
894
        }
895
        if (flags & SETUP_STATE_OVERWRITE_F)
73✔
896
            return 0;
897
        logerr(gl_LOGFILE, "Found existing TPM state '%s'.\n", TPM_PERMANENT_ALL_NAME);
3✔
898
        return 1;
3✔
899
    }
900

901
    return 0;
902
}
903

904
static void versioninfo(void)
2✔
905
{
906
    printf("TPM emulator setup tool version %d.%d.%d\n",
2✔
907
           SWTPM_VER_MAJOR, SWTPM_VER_MINOR, SWTPM_VER_MICRO);
908
}
2✔
909

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

1073
static int get_swtpm_capabilities(const gchar **swtpm_prg_l, gboolean is_tpm2,
397✔
1074
                                  gchar **standard_output)
1075
{
1076
    const gchar *my_argv[] = { "--print-capabilities", is_tpm2 ? "--tpm2" : NULL, NULL };
397✔
1077
    g_autofree gchar *standard_error = NULL;
794✔
1078
    g_autofree gchar *logop = NULL;
397✔
1079
    g_autoptr(GError) error = NULL;
397✔
1080
    g_autofree const gchar **argv = NULL;
397✔
1081
    int exit_status = 0;
397✔
1082
    gboolean success;
397✔
1083
    int ret = 1;
397✔
1084

1085
    argv = concat_arrays(swtpm_prg_l, my_argv, FALSE);
397✔
1086

1087
    if (gl_LOGFILE != NULL) {
397✔
1088
        logop = g_strdup_printf("file=%s", gl_LOGFILE);
248✔
1089
        argv = concat_arrays(argv, (const gchar*[]){"--log", logop, NULL}, TRUE);
248✔
1090
    }
1091

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

1105
error:
397✔
1106
    return ret;
397✔
1107
}
1108

1109
static int get_supported_tpm_versions(const gchar **swtpm_prg_l, gboolean *swtpm_has_tpm12,
169✔
1110
                                      gboolean *swtpm_has_tpm2)
1111
{
1112
    g_autofree gchar *standard_output = NULL;
338✔
1113
    int ret;
169✔
1114

1115
    ret = get_swtpm_capabilities(swtpm_prg_l, FALSE, &standard_output);
169✔
1116
    if (ret)
169✔
1117
        return ret;
1118

1119
    *swtpm_has_tpm12 = g_strstr_len(standard_output, -1, "\"tpm-1.2\"") != NULL;
169✔
1120
    *swtpm_has_tpm2 = g_strstr_len(standard_output, -1, "\"tpm-2.0\"") != NULL;
169✔
1121

1122
    return 0;
169✔
1123
}
1124

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

1140
    *n_keysizes = 0;
160✔
1141

1142
    if (flags & SETUP_TPM2_F) {
160✔
1143
        ret = get_swtpm_capabilities(swtpm_prg_l, TRUE, &standard_output);
134✔
1144
        if (ret)
134✔
1145
            goto error;
×
1146

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

1161
error:
160✔
1162
    return ret;
160✔
1163
}
1164

1165
/* Return the RSA key size capabilities in a NULL-terminated array */
1166
static int get_rsa_keysize_caps(unsigned long flags, const gchar **swtpm_prg_l,
9✔
1167
                                gchar ***keysize_strs)
1168
{
1169
    unsigned int *keysizes = NULL;
9✔
1170
    size_t n_keysizes = 0;
9✔
1171
    size_t i, j;
9✔
1172
    int ret = get_rsa_keysizes(flags, swtpm_prg_l, &keysizes, &n_keysizes);
9✔
1173
    if (ret)
9✔
1174
        return ret;
1175

1176
    *keysize_strs = g_malloc0(sizeof(char *) * (n_keysizes + 1));
9✔
1177
    for (i = 0, j = 0; i < n_keysizes; i++) {
45✔
1178
        if (keysizes[i] >= 2048)
36✔
1179
            (*keysize_strs)[j++] = g_strdup_printf("tpm2-rsa-keysize-%u", keysizes[i]);
27✔
1180
    }
1181

1182
    g_free(keysizes);
9✔
1183

1184
    return 0;
9✔
1185
}
1186

1187
static int validate_json_profile(const gchar **swtpm_prg_l, const char *json_profile)
85✔
1188
{
1189
    g_autofree gchar *standard_output = NULL;
170✔
1190
    int ret;
85✔
1191

1192
    ret = get_swtpm_capabilities(swtpm_prg_l, TRUE, &standard_output);
85✔
1193
    if (ret)
85✔
1194
        return ret;
1195

1196
    return check_json_profile(standard_output, json_profile);
85✔
1197
}
1198

1199
/* Print the JSON object of swtpm_setup's capabilities */
1200
static int print_capabilities(const char **swtpm_prg_l, gboolean swtpm_has_tpm12,
9✔
1201
                              gboolean swtpm_has_tpm2)
1202
{
1203
    g_autofree gchar *standard_output = NULL;
18✔
1204
    g_autofree gchar *param = g_strdup("");
18✔
1205
    g_autofree gchar *profile_list = NULL;
9✔
1206
    gchar **profile_names = NULL;
9✔
1207
    gchar **keysize_strs = NULL;
9✔
1208
    gchar *tmp;
9✔
1209
    size_t i;
9✔
1210
    int ret = 0;
9✔
1211

1212
    ret = get_rsa_keysize_caps(SETUP_TPM2_F, swtpm_prg_l, &keysize_strs);
9✔
1213
    if (ret)
9✔
1214
        return 1;
1215

1216
    for (i = 0; keysize_strs[i] != NULL; i++) {
36✔
1217
        tmp = g_strdup_printf("%s, \"%s\"", param, keysize_strs[i]);
27✔
1218
        g_free(param);
27✔
1219
        param = tmp;
27✔
1220
    }
1221

1222
    if (swtpm_has_tpm2) {
9✔
1223
        ret = get_swtpm_capabilities(swtpm_prg_l, TRUE, &standard_output);
9✔
1224
        if (ret)
9✔
1225
            goto error;
×
1226
        ret = get_profile_names(standard_output, &profile_names);
9✔
1227
        if (ret)
9✔
1228
            goto error;
×
1229

1230
        if (g_strv_length(profile_names) > 0) {
9✔
1231
            tmp = g_strjoinv("\", \"", profile_names);
9✔
1232
            profile_list = g_strdup_printf(" \"%s\" ", tmp);
9✔
1233
            g_free(tmp);
9✔
1234
        }
1235
    }
1236

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

1254
error:
9✔
1255
    g_strfreev(keysize_strs);
9✔
1256
    g_strfreev(profile_names);
9✔
1257

1258
    return ret;
9✔
1259
}
1260

1261
static int change_process_owner(const char *user)
1262
{
1263
    char *endptr;
×
1264
    unsigned long long uid = strtoull(user, &endptr, 10);
×
1265
    gid_t gid;
×
1266
    struct passwd *passwd;
×
1267
    int ret = 1;
×
1268

1269
    if (*endptr != '\0') {
×
1270
        /* assuming a name */
1271
        passwd = getpwnam(user);
×
1272
        if (passwd == NULL) {
×
1273
            logerr(gl_LOGFILE, "Error: User '%s' does not exist.\n", user);
×
1274
            goto error;
×
1275
        }
1276

1277
        if (initgroups(passwd->pw_name, passwd->pw_gid) != 0) {
×
1278
            logerr(gl_LOGFILE, "Error: initgroups() failed: %s\n", strerror(errno));
×
1279
            goto error;
×
1280
        }
1281

1282
        gid = passwd->pw_gid;
×
1283
        uid = passwd->pw_uid;
×
1284
    } else {
1285
        if (uid > 0xffffffff) {
×
1286
            logerr(gl_LOGFILE, "Error: uid %s outside valid range.\n", user);
×
1287
            goto error;
×
1288
        }
1289
        gid = (gid_t)uid;
×
1290
    }
1291

1292
    if (setgid(gid) != 0) {
×
1293
        logerr(gl_LOGFILE, "Error: setgid(%d) failed: %s\n", gid, strerror(errno));
×
1294
        goto error;
×
1295
    }
1296

1297
    if (setuid(uid) != 0) {
×
1298
        logerr(gl_LOGFILE, "Error: setuid(%d) failed: %s\n", uid, strerror(errno));
×
1299
        goto error;
×
1300
    }
1301

1302
    ret = 0;
1303

1304
error:
×
1305
    return ret;
×
1306
}
1307

1308
static int handle_create_config_files(const char *opt_arg)
1309
{
1310
    g_auto(GStrv) tokens = NULL;
×
1311
    gboolean overwrite = FALSE;
×
1312
    gboolean root_flag = FALSE;
×
1313
    gboolean skip_if_exist = FALSE;
×
1314

1315
    if (opt_arg) {
×
1316
        tokens = g_strsplit_set(opt_arg, ", ", -1);
×
1317
        overwrite = g_strv_contains((const gchar **)tokens, "overwrite");
×
1318
        root_flag = g_strv_contains((const gchar **)tokens, "root");
×
1319
        skip_if_exist = g_strv_contains((const gchar **)tokens, "skip-if-exist");
×
1320
        if (overwrite && skip_if_exist) {
×
1321
            fprintf(stderr, "Error: overwrite and skip-if-exist cannot both be used\n");
×
1322
            return 1;
×
1323
        }
1324
    }
1325

1326
    return create_config_files(overwrite, root_flag, skip_if_exist);
×
1327
}
1328

1329
static int read_config_file(const gchar *config_file,
155✔
1330
                            const struct passwd *user,
1331
                            gchar ***config_file_lines)
1332
{
1333
    if (access(config_file, R_OK) != 0) {
155✔
1334
        logerr(gl_LOGFILE, "User %s cannot read config file %s.\n",
×
1335
               user ? user->pw_name : "<unknown>", config_file);
1336
        return -1;
×
1337
    }
1338

1339
    if (read_file_lines(config_file, config_file_lines))
155✔
1340
        return -1;
×
1341

1342
    return 0;
1343
}
1344

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

1445
    setvbuf(stdout, 0, _IONBF, 0);
182✔
1446

1447
    if (init(&config_file) < 0)
182✔
1448
        goto error;
×
1449

1450
    swtpm_prg = g_find_program_in_path("swtpm");
182✔
1451
    if (swtpm_prg) {
182✔
1452
        tmp = g_strconcat(swtpm_prg, " socket", NULL);
68✔
1453
        g_free(swtpm_prg);
68✔
1454
        swtpm_prg = tmp;
68✔
1455
    }
1456

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

1658
    if (swtpm_prg == NULL) {
180✔
1659
        logerr(gl_LOGFILE,
11✔
1660
               "Default TPM 'swtpm' could not be found and was not provided using --tpm.\n");
1661
        goto error;
11✔
1662
    }
1663

1664
    swtpm_prg_l = split_cmdline(swtpm_prg);
169✔
1665
    tmp = g_find_program_in_path(swtpm_prg_l[0]);
169✔
1666
    if (!tmp) {
169✔
1667
        logerr(gl_LOGFILE, "swtpm at %s is not an executable.\n", swtpm_prg_l[0]);
×
1668
        goto error;
×
1669
    }
1670
    g_free(tmp);
169✔
1671

1672
    ret = get_supported_tpm_versions((const char **)swtpm_prg_l, &swtpm_has_tpm12, &swtpm_has_tpm2);
169✔
1673
    if (ret != 0)
169✔
1674
        goto error;
×
1675

1676
    if (printcapabilities) {
169✔
1677
        ret = print_capabilities((const char **)swtpm_prg_l, swtpm_has_tpm12, swtpm_has_tpm2);
9✔
1678
        goto out;
9✔
1679
    }
1680

1681
    if ((flags & SETUP_TPM2_F) != 0 && !swtpm_has_tpm2) {
160✔
1682
        logerr(gl_LOGFILE, "swtpm at %s does not support TPM 2\n", swtpm_prg_l[0]);
×
1683
        goto error;
×
1684
    } else if ((flags & SETUP_TPM2_F) == 0 && !swtpm_has_tpm12){
160✔
1685
        logerr(gl_LOGFILE, "swtpm at %s does not support TPM 1.2\n", swtpm_prg_l[0]);
×
1686
        goto error;
×
1687
    }
1688

1689
    if (runas) {
160✔
1690
        ret = change_process_owner(runas);
×
1691
        if (ret != 0)
×
1692
            goto error;
×
1693
    }
1694

1695
    curr_user = getpwuid(getuid());
160✔
1696

1697
    if (printprofiles) {
160✔
1698
        ret = 0;
3✔
1699
        if (read_config_file(config_file, curr_user, &config_file_lines) < 0)
3✔
1700
            goto error;
×
1701

1702
        if (flags & SETUP_TPM2_F) {
3✔
1703
            if (profile_printall((const char **)swtpm_prg_l, config_file_lines))
3✔
1704
                ret = 1;
3✔
1705
        } else {
1706
            printf("{}\n");
×
1707
        }
1708
        goto out;
3✔
1709
    }
1710

1711
    if (!got_ownerpass)
157✔
1712
        ownerpass = g_strdup(DEFAULT_OWNER_PASSWORD);
153✔
1713
    if (!got_srkpass)
157✔
1714
        srkpass = g_strdup(DEFAULT_SRK_PASSWORD);
153✔
1715

1716
    if (gl_LOGFILE != NULL) {
157✔
1717
        FILE *tmpfile;
93✔
1718
        if (stat(gl_LOGFILE, &statbuf) == 0 &&
93✔
1719
            (statbuf.st_mode & S_IFMT) == S_IFLNK) {
93✔
1720
            fprintf(stderr, "Logfile must not be a symlink.\n");
×
1721
            goto error;
×
1722
        }
1723
        tmpfile = fopen(gl_LOGFILE, "a");
93✔
1724
        if (tmpfile == NULL) {
93✔
1725
            fprintf(stderr, "Cannot write to logfile %s.\n", gl_LOGFILE);
×
1726
            goto error;
×
1727
        }
1728
        fclose(tmpfile);
93✔
1729
    }
1730

1731
    // Check tpm_state_path directory and access rights
1732
    if (tpm_state_path == NULL) {
157✔
1733
        logerr(gl_LOGFILE, "--tpm-state must be provided\n");
×
1734
        goto error;
×
1735
    }
1736

1737
    backend_state = backend_ops->parse_backend(tpm_state_path);
157✔
1738
    if (!backend_state)
157✔
1739
        goto error;
×
1740

1741
    if (backend_ops->check_access(backend_state, R_OK|W_OK, curr_user) != 0)
157✔
1742
        goto error;
×
1743

1744
    if ((flags & SETUP_WRITE_EK_CERT_FILES_F)) {
157✔
1745
        if (check_directory_access(user_certsdir, W_OK, curr_user) != 0)
6✔
1746
            goto error;
×
1747
    }
1748

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

1781
    if (!(flags & SETUP_RECONFIGURE_F)) {
157✔
1782
        ret = check_state_overwrite((const char **)swtpm_prg_l, flags, tpm_state_path);
151✔
1783
        if (ret == 1) {
151✔
1784
            goto error;
3✔
1785
        } else if (ret == 2) {
148✔
1786
            ret = 0;
2✔
1787
            goto out;
2✔
1788
        }
1789

1790
        ret = backend_ops->delete_state(backend_state);
146✔
1791
        if (ret != 0)
146✔
1792
            goto error;
×
1793
    }
1794

1795
    if (!config_file_lines &&
304✔
1796
        read_config_file(config_file, curr_user, &config_file_lines) < 0)
152✔
1797
        goto error;
×
1798

1799
    /* check pcr_banks; read from config file if not given */
1800
    tmp_l = g_strsplit(pcr_banks ? pcr_banks : "", ",", -1);
152✔
1801
    for (i = 0, n = 0; tmp_l[i]; i++) {
318✔
1802
        g_strstrip(tmp_l[i]);
14✔
1803
        n += strlen(tmp_l[i]);
14✔
1804
    }
1805
    g_strfreev(tmp_l);
152✔
1806
    if (n == 0) {
152✔
1807
        g_free(pcr_banks);
144✔
1808
        pcr_banks = get_default_pcr_banks(config_file_lines);
144✔
1809
    }
1810

1811
    if ((json_profile != NULL) +
152✔
1812
        (json_profile_name != NULL) +
152✔
1813
        (json_profile_file != NULL) +
152✔
1814
        (json_profile_fd > 0) > 1) {
152✔
1815
        logerr(gl_LOGFILE, "Only one of --profile, --profile-name, --profile-file, and --profile-file-fd may be given.\n");
×
1816
        goto error;
×
1817
    }
1818

1819
    if ((flags & SETUP_RECONFIGURE_F) &&
152✔
1820
         (json_profile ||
6✔
1821
          json_profile_name ||
6✔
1822
          json_profile_file ||
6✔
1823
          json_profile_fd > 0)) {
1824
            logerr(gl_LOGFILE, "Reconfiguration does not accept a (new) profile.\n");
×
1825
            goto error;
×
1826
    }
1827

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

1845
    if (json_profile_file) {
152✔
1846
        json_profile_fd = open(json_profile_file, O_RDONLY);
5✔
1847
        if (json_profile_fd < 0) {
5✔
1848
            logerr(gl_LOGFILE, "Could not open profile file '%s': %s\n",
×
1849
                   json_profile_file, strerror(errno));
×
1850
            goto error;
×
1851
        }
1852
    }
1853

1854
    /*
1855
     * Read default profile from swtpm_setup.conf;
1856
     * Do not read it when --reconfigure'ing
1857
     */
1858
    if ((flags & SETUP_TPM2_F) != 0 &&
152✔
1859
        json_profile == NULL && json_profile_fd < 0 &&
126✔
1860
        (flags & SETUP_RECONFIGURE_F) == 0) {
1861

1862
        json_profile_fd = get_default_profile_fd(config_file_lines);
43✔
1863
        if (json_profile_fd == -2)
43✔
1864
            goto error;
×
1865
        if (json_profile_fd < 0)
43✔
1866
            json_profile = get_default_profile(config_file_lines);
43✔
1867
    }
1868

1869
    if (json_profile_fd >= 0)
152✔
1870
        fds_to_pass[n_fds_to_pass++] = json_profile_fd;
5✔
1871

1872
    if ((flags & SETUP_TPM2_F) != 0 && json_profile) {
152✔
1873
        if (validate_json_profile((const char **)swtpm_prg_l, json_profile) != 0)
85✔
1874
            goto error;
1✔
1875
    } else if (json_profile) {
67✔
1876
        logerr(gl_LOGFILE, "There's no --profile support for TPM 1.2\n");
×
1877
        goto error;
×
1878
    }
1879

1880
    if (cipher != NULL) {
151✔
1881
        if (strcmp(cipher, "aes-128-cbc") != 0 &&
151✔
1882
            strcmp(cipher, "aes-cbc") != 0 &&
13✔
1883
            strcmp(cipher, "aes-256-cbc") != 0) {
13✔
1884
            logerr(gl_LOGFILE, "Unsupported cipher %s.\n", cipher);
×
1885
            goto error;
×
1886
        }
1887
        tmp = g_strdup_printf(",mode=%s", cipher);
151✔
1888
        g_free(cipher);
151✔
1889
        cipher = tmp;
151✔
1890
    }
1891

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

1918
    if ((flags & SETUP_RSA_KEYSIZE_BY_USER_F) == 0)
151✔
1919
        rsa_keysize_str = get_default_rsa_keysize(config_file_lines);
131✔
1920

1921
    if (strcmp(rsa_keysize_str, "max") == 0) {
151✔
1922
        unsigned int *keysizes = NULL;
×
1923
        size_t n_keysizes;
×
1924

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

1944
        ret = get_rsa_keysizes(flags, (const char **)swtpm_prg_l, &keysizes, &n_keysizes);
151✔
1945
        if (ret)
151✔
1946
            goto error;
×
1947

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

1961
    if (flags & SETUP_RECONFIGURE_F) {
151✔
1962
        if (flags & (SETUP_CREATE_EK_F | SETUP_EK_CERT_F | SETUP_PLATFORM_CERT_F)) {
6✔
1963
            logerr(gl_LOGFILE, "Reconfiguration is not supported with creation of EK or certificates\n");
×
1964
            goto error;
×
1965
        }
1966
    }
1967

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

1981
    if (flags & (SETUP_EK_CERT_F | SETUP_PLATFORM_CERT_F)) {
151✔
1982
        certsdir = g_dir_make_tmp("swtpm_setup.certs.XXXXXX", &error);
47✔
1983
        if (certsdir == NULL) {
47✔
1984
            logerr(gl_LOGFILE, "Could not create temporary directory for certs: %s\n",
×
1985
                   error->message);
×
1986
            goto error;
×
1987
        }
1988
    }
1989

1990
    if ((flags & SETUP_TPM2_F) == 0) {
151✔
1991
        ret = init_tpm(flags, swtpm_prg_l, config_file, tpm_state_path, ownerpass, srkpass, vmid,
26✔
1992
                       swtpm_keyopt, fds_to_pass, n_fds_to_pass, certsdir, user_certsdir);
1993
    } else {
1994
        ret = init_tpm2(flags, swtpm_prg_l, config_file, tpm_state_path, vmid, pcr_banks,
125✔
1995
                       swtpm_keyopt, fds_to_pass, n_fds_to_pass, rsa_keysize, certsdir,
1996
                       user_certsdir, json_profile, json_profile_fd,
1997
                       profile_remove_disabled_param);
1998
    }
1999

2000
    if (ret == 0) {
151✔
2001
        logit(gl_LOGFILE, "Successfully authored TPM state.\n");
143✔
2002
    } else {
2003
        logerr(gl_LOGFILE, "An error occurred. Authoring the TPM state failed.\n");
8✔
2004
        backend_ops->delete_state(backend_state);
8✔
2005
    }
2006

2007
    now = time(NULL);
151✔
2008
    tm = localtime(&now);
151✔
2009
    if (strftime(tmpbuffer, sizeof(tmpbuffer), "%a %d %h %Y %I:%M:%S %p %Z", tm) == 0) {
151✔
2010
        logerr(gl_LOGFILE, "Could not format time/date string.\n");
×
2011
        goto error;
×
2012
    }
2013
    logit(gl_LOGFILE, "Ending vTPM manufacturing @ %s\n",
151✔
2014
          tmpbuffer);
2015

2016
out:
182✔
2017
    if (certsdir && g_rmdir(certsdir) != 0)
182✔
2018
        logerr(gl_LOGFILE, "Could not remove temporary directory for certs: %s\n",
×
2019
               strerror(errno));
×
2020

2021
    if (backend_ops && backend_state)
182✔
2022
        backend_ops->free_backend(backend_state);
157✔
2023
    g_strfreev(swtpm_prg_l);
182✔
2024
    g_free(gl_LOGFILE);
182✔
2025

2026
    return ret;
182✔
2027

2028
error:
15✔
2029
    ret = 1;
15✔
2030
    goto out;
15✔
2031
}
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