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

stefanberger / swtpm / 621325588

05 May 2024 09:04PM UTC coverage: 73.542% (+0.2%) from 73.324%
621325588

push

travis-ci

web-flow
Merge defd1f468 into bfd6b8270

7163 of 9740 relevant lines covered (73.54%)

14121.07 hits per line

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

78.13
/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 "swtpm.h"
36
#include "swtpm_conf.h"
37
#include "swtpm_utils.h"
38
#include "swtpm_setup_utils.h"
39

40
#include <openssl/sha.h>
41

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

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

64
/* default configuration file */
65
#define SWTPM_SETUP_CONF "swtpm_setup.conf"
66

67
/* Default logging goes to stderr */
68
gchar *gl_LOGFILE = NULL;
69

70
#define DEFAULT_RSA_KEYSIZE 2048
71

72

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

83
/* initialize the path of the config_file */
84
static int init(gchar **config_file)
97✔
85
{
86
    const gchar *configdir = g_get_user_config_dir();
97✔
87

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

94
    return 0;
97✔
95
}
96

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

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

128
    jp = json_parser_new();
74✔
129

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

136
    *params = NULL;
74✔
137
    root = json_parser_get_root(jp);
74✔
138

139
    for (idx = 0; parser_rules[idx].node1 != NULL; idx++) {
592✔
140
        jr = json_reader_new(root);
444✔
141
        if (json_reader_read_member(jr, parser_rules[idx].node1) &&
888✔
142
            json_reader_read_member(jr, parser_rules[idx].node2)) {
444✔
143
            gchar *str;
444✔
144

145
            if (parser_rules[idx].is_int)
444✔
146
                str = g_strdup_printf("%ld", (long)json_reader_get_int_value(jr));
148✔
147
            else
148
                str = g_strdup(json_reader_get_string_value(jr));
296✔
149

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

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

174
    return ret;
74✔
175
}
176

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

195
    ret = tpm_get_specs_and_attributes(swtpm, &params);
74✔
196
    if (ret != 0)
74✔
197
        goto error;
×
198

199
    ret = read_file_lines(configfile, &config_file_lines);
74✔
200
    if (ret != 0)
74✔
201
        goto error;
×
202

203
    create_certs_tool = get_config_value(config_file_lines, "create_certs_tool");
74✔
204
    create_certs_tool_config = get_config_value(config_file_lines, "create_certs_tool_config");
74✔
205
    create_certs_tool_options = get_config_value(config_file_lines, "create_certs_tool_options");
74✔
206

207
    ret = 0;
74✔
208

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

217
        if (flags & SETUP_TPM2_F) {
74✔
218
            params = concat_arrays(params,
66✔
219
                                (gchar*[]){
66✔
220
                                    g_strdup("--tpm2"),
66✔
221
                                    NULL
222
                                }, TRUE);
223
        }
224
        cmd = concat_arrays((gchar*[]) {
74✔
225
                                create_certs_tool_path,
226
                                "--type", "_",  /* '_' must be at index '2' ! */
227
                                "--ek", (gchar *)ekparam,
228
                                "--dir", (gchar *)certsdir,
229
                                NULL
230
                            }, NULL, FALSE);
231
        if (gl_LOGFILE != NULL)
74✔
232
            cmd = concat_arrays(cmd, (gchar*[]){"--logfile", (gchar *)gl_LOGFILE, NULL}, TRUE);
9✔
233
        if (vmid != NULL)
74✔
234
            cmd = concat_arrays(cmd, (gchar*[]){"--vmid", (gchar *)vmid, NULL}, TRUE);
65✔
235
        cmd = concat_arrays(cmd, params, TRUE);
74✔
236
        if (create_certs_tool_config != NULL)
74✔
237
            cmd = concat_arrays(cmd, (gchar*[]){"--configfile", create_certs_tool_config, NULL}, TRUE);
9✔
238
        if (create_certs_tool_options != NULL)
74✔
239
            cmd = concat_arrays(cmd, (gchar*[]){"--optsfile", create_certs_tool_options, NULL}, TRUE);
9✔
240

241
        s = g_strrstr(create_certs_tool, G_DIR_SEPARATOR_S);
74✔
242
        if (s)
74✔
243
            prgname = strdup(&s[1]);
9✔
244
        else
245
            prgname = strdup(create_certs_tool);
65✔
246

247
        for (idx = 0; flags_to_certfiles[idx].filename != NULL; idx++) {
222✔
248
            if (cert_flags & flags_to_certfiles[idx].flag) {
148✔
249
                g_autofree gchar *standard_output = NULL;
114✔
250
                g_autofree gchar *standard_error = NULL;
114✔
251
                GError *error = NULL;
114✔
252
                gchar **lines;
114✔
253

254
                cmd[2] = (gchar *)flags_to_certfiles[idx].type; /* replaces the "_" above */
114✔
255

256
                s = g_strjoinv(" ", cmd);
114✔
257
                logit(gl_LOGFILE, "  Invoking %s\n", s);
114✔
258
                g_free(s);
114✔
259

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

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

282
                SWTPM_G_FREE(standard_output);
114✔
283
                SWTPM_G_FREE(standard_error);
114✔
284
            }
285
        }
286
    }
287

288
error:
×
289
    g_strfreev(config_file_lines);
74✔
290
    g_strfreev(params);
74✔
291

292
    return ret;
74✔
293
}
294

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

301
    return g_strjoin(G_DIR_SEPARATOR_S, user_certsdir, filename, NULL);
9✔
302
}
303

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

317
    if (preserve && (flags & SETUP_WRITE_EK_CERT_FILES_F) && user_certsdir != NULL) {
114✔
318
        if (!g_file_get_contents(certfile, &content, &content_length, &error))
9✔
319
            goto error;
×
320

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

338
    return 0;
114✔
339

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

344
error_unlink:
×
345
    unlink(certfile);
×
346

347
    return 1;
×
348
}
349

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

356
    return read_file(*certfile, filecontent, filecontent_len);
114✔
357
}
358

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

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

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

391
    if (ret != 0)
99✔
392
        goto error_unlink;
×
393

394
    return certfile_move_or_delete(flags, !!(ftc->flag & SETUP_EK_CERT_F),
99✔
395
                                   certfile, user_certsdir,
396
                                   key_type, key_description);
397

398
error_unlink:
×
399
    unlink(certfile);
×
400
    return 1;
×
401
}
402

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

416
    if (flags & SETUP_CREATE_EK_F) {
82✔
417
        ret = swtpm2->ops->create_ek(&swtpm2->swtpm, !!(flags & SETUP_TPM2_ECC_F), rsa_keysize,
156✔
418
                                     !!(flags & SETUP_ALLOW_SIGNING_F),
78✔
419
                                     !!(flags & SETUP_DECRYPTION_F),
78✔
420
                                     !!(flags & SETUP_LOCK_NVRAM_F),
78✔
421
                                     &ekparam, &key_description);
422
        if (ret != 0)
78✔
423
            return 1;
424
    }
425

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

434
        for (idx = 0; flags_to_certfiles[idx].filename; idx++) {
198✔
435
            if (cert_flags & flags_to_certfiles[idx].flag) {
132✔
436
                key_type = flags_to_certfiles[idx].flag & SETUP_EK_CERT_F ? "ek" : "";
99✔
437

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

447
    return 0;
448
}
449

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

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

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

471
/* Get the default PCR banks from the config file and if nothing can
472
   be found there use the DEFAULT_PCR_BANKS #define.
473
 */
474
static gchar *get_default_pcr_banks(const gchar *config_file)
67✔
475
{
476
    g_auto(GStrv) config_file_lines = NULL;
134✔
477
    gchar *pcr_banks;
67✔
478
    int ret;
67✔
479

480
    ret = read_file_lines(config_file, &config_file_lines);
67✔
481
    if (ret != 0)
67✔
482
        return NULL;
483

484
    pcr_banks = get_config_value(config_file_lines, "active_pcr_banks");
67✔
485
    if (pcr_banks)
67✔
486
        g_strstrip(pcr_banks);
26✔
487
    if (pcr_banks == NULL || strlen(pcr_banks) == 0) {
67✔
488
        g_free(pcr_banks);
41✔
489
        pcr_banks = g_strdup(DEFAULT_PCR_BANKS);
41✔
490
    }
491
    return pcr_banks;
492
}
493

494
/* Activate the given list of PCR banks. If pcr_banks is '-' then leave
495
 * the configuration as-is.
496
 */
497
static int tpm2_activate_pcr_banks(struct swtpm2 *swtpm2,
47✔
498
                                   const gchar *pcr_banks)
499
{
500
    g_autofree gchar *active_pcr_banks_join = NULL;
94✔
501
    g_autofree gchar *all_pcr_banks_join = NULL;
47✔
502
    g_auto(GStrv) active_pcr_banks = NULL;
47✔
503
    g_auto(GStrv) all_pcr_banks = NULL;
47✔
504
    g_auto(GStrv) pcr_banks_l = NULL;
47✔
505
    struct swtpm *swtpm = &swtpm2->swtpm;
47✔
506
    int ret = 0;
47✔
507

508
    if (g_str_equal(pcr_banks, "-"))
47✔
509
        return 0;
510

511
    ret = swtpm2->ops->get_all_pcr_banks(swtpm, &all_pcr_banks);
47✔
512
    if (ret != 0)
47✔
513
        return ret;
514

515
    pcr_banks_l = g_strsplit(pcr_banks, ",", -1);
47✔
516
    ret = swtpm2->ops->set_active_pcr_banks(swtpm, pcr_banks_l, all_pcr_banks,
47✔
517
                                            &active_pcr_banks);
518
    if (ret != 0)
47✔
519
        return ret;
520

521
    active_pcr_banks_join = g_strjoinv(",", active_pcr_banks);
47✔
522
    all_pcr_banks_join = g_strjoinv(",", all_pcr_banks);
47✔
523
    logit(gl_LOGFILE, "Successfully activated PCR banks %s among %s.\n",
47✔
524
          active_pcr_banks_join, all_pcr_banks_join);
525

526
    return 0;
47✔
527
}
528

529
/* Simulate manufacturing a TPM 2: create keys and certificates */
530
static int init_tpm2(unsigned long flags, gchar **swtpm_prg_l, const gchar *config_file,
47✔
531
                     const gchar *tpm2_state_path, const gchar *vmid, const gchar *pcr_banks,
532
                     const gchar *swtpm_keyopt, int *fds_to_pass, size_t n_fds_to_pass,
533
                     unsigned int rsa_keysize, const gchar *certsdir,
534
                     const gchar *user_certsdir)
535
{
536
    struct swtpm2 *swtpm2;
47✔
537
    struct swtpm *swtpm;
47✔
538
    int ret;
47✔
539

540
    swtpm2 = swtpm2_new(swtpm_prg_l, tpm2_state_path, swtpm_keyopt, gl_LOGFILE,
47✔
541
                        fds_to_pass, n_fds_to_pass);
542
    if (swtpm2 == NULL)
47✔
543
        return 1;
544
    swtpm = &swtpm2->swtpm;
47✔
545

546
    ret = swtpm->cops->start(swtpm);
47✔
547
    if (ret != 0) {
47✔
548
        logerr(gl_LOGFILE, "Could not start the TPM 2.\n");
×
549
        goto error;
×
550
    }
551

552
    if (!(flags & SETUP_RECONFIGURE_F)) {
47✔
553
        if ((flags & SETUP_CREATE_SPK_F)) {
41✔
554
            ret = swtpm2->ops->create_spk(swtpm, !!(flags & SETUP_TPM2_ECC_F), rsa_keysize);
3✔
555
            if (ret != 0)
3✔
556
                goto destroy;
×
557
        }
558

559
        ret = tpm2_create_eks_and_certs(flags, config_file, certsdir, vmid, rsa_keysize, swtpm2,
41✔
560
                                        user_certsdir);
561
        if (ret != 0)
41✔
562
            goto destroy;
×
563
    }
564

565
    ret = tpm2_activate_pcr_banks(swtpm2, pcr_banks);
47✔
566
    if (ret != 0)
47✔
567
        goto destroy;
×
568

569
    ret = swtpm2->ops->shutdown(swtpm);
47✔
570

571
destroy:
47✔
572
    swtpm->cops->destroy(swtpm);
47✔
573

574
error:
47✔
575
    swtpm_free(swtpm);
47✔
576

577
    return ret;
47✔
578
}
579

580
/* Create the owner password digest */
581
static void tpm12_get_ownerpass_digest(unsigned long flags, const gchar *ownerpass,
9✔
582
                                       unsigned char ownerpass_digest[SHA_DIGEST_LENGTH])
583
{
584
    const gchar zeros[SHA_DIGEST_LENGTH]= {0, };
9✔
585
    size_t len;
9✔
586

587
    if (ownerpass == NULL) {
9✔
588
        if (flags & SETUP_OWNERPASS_ZEROS_F) {
2✔
589
            ownerpass = zeros;
590
            len = sizeof(zeros);
591
        } else {
592
            ownerpass = DEFAULT_OWNER_PASSWORD;
×
593
            len = strlen(ownerpass);
×
594
        }
595
    } else {
596
        len = strlen(ownerpass);
7✔
597
    }
598
    SHA1((const unsigned char *)ownerpass, len, ownerpass_digest);
9✔
599
}
9✔
600

601
/* Create the SRK password digest */
602
static void tpm12_get_srkpass_digest(unsigned long flags, const gchar *srkpass,
9✔
603
                                     unsigned char srkpass_digest[SHA_DIGEST_LENGTH])
604
{
605
    const gchar zeros[SHA_DIGEST_LENGTH]= {0, };
9✔
606
    size_t len;
9✔
607

608
    if (srkpass == NULL) {
9✔
609
        if (flags & SETUP_SRKPASS_ZEROS_F) {
2✔
610
            srkpass = zeros;
611
            len = sizeof(zeros);
612
        } else {
613
            srkpass = DEFAULT_SRK_PASSWORD;
×
614
            len = strlen(srkpass);
×
615
        }
616
    } else {
617
        len = strlen(srkpass);
7✔
618
    }
619
    SHA1((const unsigned char *)srkpass, len, srkpass_digest);
9✔
620
}
9✔
621

622
/* Take ownership of a TPM 1.2 */
623
static int tpm12_take_ownership(unsigned long flags, const gchar *ownerpass,
9✔
624
                                const gchar *srkpass, gchar *pubek, size_t pubek_len,
625
                                struct swtpm12 *swtpm12)
626
{
627
    unsigned char ownerpass_digest[SHA_DIGEST_LENGTH];
9✔
628
    unsigned char srkpass_digest[SHA_DIGEST_LENGTH];
9✔
629

630
    tpm12_get_ownerpass_digest(flags, ownerpass, ownerpass_digest);
9✔
631
    tpm12_get_srkpass_digest(flags, srkpass, srkpass_digest);
9✔
632

633
    return swtpm12->ops->take_ownership(&swtpm12->swtpm, ownerpass_digest, srkpass_digest,
9✔
634
                                        (const unsigned char *)pubek, pubek_len);
635
}
636

637
/* Create the certificates for a TPM 1.2 */
638
static int tpm12_create_certs(unsigned long flags, const gchar *config_file,
8✔
639
                              const gchar *certsdir, const gchar *ekparam,
640
                              const gchar *vmid, struct swtpm12 *swtpm12,
641
                              const gchar *user_certsdir)
642
{
643
    g_autofree gchar *filecontent = NULL;
16✔
644
    g_autofree gchar *certfile = NULL;
8✔
645
    unsigned int cert_flags;
8✔
646
    const gchar *key_type;
8✔
647
    gsize filecontent_len;
8✔
648
    size_t idx;
8✔
649
    int ret;
8✔
650

651
    /* TPM 1.2 only has ek and platform certs */
652
    cert_flags = flags & (SETUP_EK_CERT_F | SETUP_PLATFORM_CERT_F);
8✔
653

654
    ret = call_create_certs(flags, cert_flags, config_file, certsdir, ekparam,
8✔
655
                            vmid, &swtpm12->swtpm);
656
    if (ret != 0)
8✔
657
        return 1;
658

659
    for (idx = 0; flags_to_certfiles[idx].filename; idx++) {
24✔
660
        if (cert_flags & flags_to_certfiles[idx].flag) {
16✔
661
            SWTPM_G_FREE(filecontent);
15✔
662
            SWTPM_G_FREE(certfile);
15✔
663

664
            ret = read_certificate_file(certsdir, flags_to_certfiles[idx].filename,
15✔
665
                                        &filecontent, &filecontent_len, &certfile);
666
            if (ret != 0)
15✔
667
                return 1;
668

669
            if (flags_to_certfiles[idx].flag == SETUP_EK_CERT_F) {
15✔
670
                ret = swtpm12->ops->write_ek_cert_nvram(&swtpm12->swtpm,
8✔
671
                                                (const unsigned char*)filecontent, filecontent_len);
672
                if (ret == 0)
8✔
673
                    logit(gl_LOGFILE, "Successfully created NVRAM area for EK certificate.\n");
8✔
674
            } else {
675
                ret = swtpm12->ops->write_platform_cert_nvram(&swtpm12->swtpm,
7✔
676
                                                  (const unsigned char*)filecontent, filecontent_len);
677
                if (ret == 0)
7✔
678
                    logit(gl_LOGFILE, "Successfully created NVRAM area for Platform certificate.\n");
7✔
679
            }
680

681
            if (ret != 0) {
15✔
682
                unlink(certfile);
×
683
                return 1;
×
684
            }
685

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

688
            if (certfile_move_or_delete(flags, !!(flags_to_certfiles[idx].flag & SETUP_EK_CERT_F),
15✔
689
                                        certfile, user_certsdir, key_type, "rsa2048") != 0)
690
                return 1;
691
        }
692
    }
693

694
    return 0;
695
}
696

697
/* Simulate manufacturing a TPM 1.2: create keys and certificate and possibly take ownership */
698
static int init_tpm(unsigned long flags, gchar **swtpm_prg_l, const gchar *config_file,
26✔
699
                    const gchar *tpm_state_path, const gchar *ownerpass, const gchar *srkpass,
700
                    const gchar *vmid, const gchar *swtpm_keyopt,
701
                    int *fds_to_pass, size_t n_fds_to_pass, const gchar *certsdir,
702
                    const gchar *user_certsdir)
703
{
704
    struct swtpm12 *swtpm12;
26✔
705
    struct swtpm *swtpm;
26✔
706
    g_autofree gchar *pubek = NULL;
52✔
707
    size_t pubek_len = 0;
26✔
708
    int ret = 1;
26✔
709

710
    swtpm12 = swtpm12_new(swtpm_prg_l, tpm_state_path, swtpm_keyopt, gl_LOGFILE,
26✔
711
                          fds_to_pass, n_fds_to_pass);
712
    if (swtpm12 == NULL)
26✔
713
        return 1;
714
    swtpm = &swtpm12->swtpm;
26✔
715

716
    ret = swtpm->cops->start(swtpm);
26✔
717
    if (ret != 0) {
26✔
718
        logerr(gl_LOGFILE, "Could not start the TPM 1.2.\n");
×
719
        goto error;
×
720
    }
721

722
    ret = swtpm12->ops->run_swtpm_bios(swtpm);
26✔
723
    if (ret != 0)
26✔
724
         goto destroy;
×
725

726
    if ((flags & SETUP_CREATE_EK_F)) {
26✔
727
        ret = swtpm12->ops->create_endorsement_key_pair(swtpm, &pubek, &pubek_len);
19✔
728
        if (ret != 0)
19✔
729
            goto destroy;
×
730

731
        logit(gl_LOGFILE, "Successfully created EK.\n");
19✔
732

733
        /* can only take owernship if created an EK */
734
        if ((flags & SETUP_TAKEOWN_F)) {
19✔
735
            ret = tpm12_take_ownership(flags, ownerpass, srkpass, pubek, pubek_len, swtpm12);
9✔
736
            if (ret != 0)
9✔
737
                goto destroy;
×
738

739
            logit(gl_LOGFILE, "Successfully took ownership of the TPM.\n");
9✔
740
        }
741

742
        /* can only create EK cert if created an EK */
743
        if ((flags & SETUP_EK_CERT_F)) {
19✔
744
            g_autofree gchar *ekparam = print_as_hex((unsigned char *)pubek, pubek_len);
16✔
745

746
            ret = tpm12_create_certs(flags, config_file, certsdir, ekparam, vmid, swtpm12,
8✔
747
                                     user_certsdir);
748
            if (ret != 0)
8✔
749
                goto destroy;
×
750
        }
751
    }
752

753
    if ((flags & SETUP_LOCK_NVRAM_F)) {
26✔
754
        ret = swtpm12->ops->nv_lock(swtpm);
12✔
755
        if (ret == 0)
12✔
756
            logit(gl_LOGFILE, "Successfully locked NVRAM access.\n");
12✔
757
    }
758

759
destroy:
14✔
760
    swtpm->cops->destroy(swtpm);
26✔
761

762
error:
26✔
763
    swtpm_free(swtpm);
26✔
764

765
    return ret;
26✔
766
}
767

768
/* Check whether we are allowed to overwrite existing state.
769
 * This function returns 2 if the state exists but flag is set to not to overwrite it,
770
 * 0 in case we can overwrite it, 1 if the state exists.
771
 */
772
static int check_state_overwrite(gchar **swtpm_prg_l, unsigned int flags,
72✔
773
                                 const char *tpm_state_path)
774
{
775
    gboolean success;
72✔
776
    g_autofree gchar *standard_output = NULL;
144✔
777
    int exit_status = 0;
72✔
778
    g_autoptr(GError) error = NULL;
72✔
779
    g_autofree gchar **argv = NULL;
72✔
780
    g_autofree gchar *statearg = g_strdup_printf("backend-uri=%s", tpm_state_path);
144✔
781
    g_autofree gchar *logop = NULL;
72✔
782
    g_autofree gchar **my_argv = NULL;
72✔
783

784
    my_argv = concat_arrays((gchar*[]) {
72✔
785
                                "--print-states",
786
                                "--tpmstate",
787
                                statearg,
788
                                NULL
789
                            }, NULL, FALSE);
790

791
    if (flags & SETUP_TPM2_F)
72✔
792
        my_argv = concat_arrays(my_argv, (gchar*[]) { "--tpm2", NULL }, TRUE);
43✔
793

794
    if (gl_LOGFILE != NULL) {
72✔
795
        logop = g_strdup_printf("file=%s", gl_LOGFILE);
14✔
796
        my_argv = concat_arrays(my_argv, (gchar*[]){"--log", logop, NULL}, TRUE);
14✔
797
    }
798

799
    argv = concat_arrays(swtpm_prg_l, my_argv, FALSE);
72✔
800

801
    success = g_spawn_sync(NULL, argv, NULL, G_SPAWN_STDERR_TO_DEV_NULL, NULL, NULL,
72✔
802
                           &standard_output, NULL, &exit_status, &error);
803
    if (!success) {
72✔
804
        logerr(gl_LOGFILE, "Could not start swtpm '%s': %s\n", swtpm_prg_l[0], error->message);
×
805
        return 1;
×
806
    }
807

808
    if (exit_status != 0) {
72✔
809
        logerr(gl_LOGFILE, "%s exit with status %d: %s\n",
×
810
               swtpm_prg_l[0], exit_status, standard_output);
811
        return 1;
×
812
    }
813

814
    if (g_strstr_len(standard_output, -1, TPM_PERMANENT_ALL_NAME) != NULL) {
72✔
815
        /* State file exists */
816
        if (flags & SETUP_STATE_NOT_OVERWRITE_F) {
11✔
817
            logit(gl_LOGFILE, "Not overwriting existing state file.\n");
2✔
818
            return 2;
2✔
819
        }
820
        if (flags & SETUP_STATE_OVERWRITE_F)
9✔
821
            return 0;
822
        logerr(gl_LOGFILE, "Found existing TPM state '%s'.\n", TPM_PERMANENT_ALL_NAME);
3✔
823
        return 1;
3✔
824
    }
825

826
    return 0;
827
}
828

829
static void versioninfo(void)
2✔
830
{
831
    printf("TPM emulator setup tool version %d.%d.%d\n",
2✔
832
           SWTPM_VER_MAJOR, SWTPM_VER_MINOR, SWTPM_VER_MICRO);
833
}
2✔
834

835
static void usage(const char *prgname, const char *default_config_file)
1✔
836
{
837
    versioninfo();
1✔
838
    printf(
1✔
839
        "Usage: %s [options]\n"
840
        "\n"
841
        "The following options are supported:\n"
842
        "\n"
843
        "--runas <user>   : Run this program under the given user's account.\n"
844
        "\n"
845
        "--tpm-state <dir>: Path where the TPM's state will be written to;\n"
846
        "                   this is a mandatory argument. Prefix with dir:// to\n"
847
        "                   use directory backend, or file:// to use linear file.\n"
848
        "\n"
849
        "--tpmstate <dir> : This is an alias for --tpm-state <dir>.\n"
850
        "\n"
851
        "--tpm <executable>\n"
852
        "                 : Path to the TPM executable; this is an optional argument and\n"
853
        "                   by default 'swtpm' in the PATH is used.\n"
854
        "\n"
855
        "--swtpm_ioctl <executable>\n"
856
        "                 : Path to the swtpm_ioctl executable; this is deprecated\n"
857
        "                   argument.\n"
858
        "\n"
859
        "--tpm2           : Setup a TPM 2; by default a TPM 1.2 is setup.\n"
860
        "\n"
861
        "--createek       : Create the EK; for a TPM 2 an RSA and ECC EK will be\n"
862
        "                   created\n"
863
        "\n"
864
        "--allow-signing  : Create an EK that can be used for signing;\n"
865
        "                   this option requires --tpm2.\n"
866
        "                   Note: Careful, this option will create a non-standard EK!\n"
867
        "\n"
868
        "--decryption     : Create an EK that can be used for key encipherment;\n"
869
        "                   this is the default unless --allow-signing is given;\n"
870
        "                   this option requires --tpm2.\n"
871
        "\n"
872
        "--ecc            : This option allows to create a TPM 2's ECC key as storage\n"
873
        "                   primary key; a TPM 2 always gets an RSA and an ECC EK key.\n"
874
        "\n"
875
        "--take-ownership : Take ownership; this option implies --createek\n"
876
        "  --ownerpass  <password>\n"
877
        "                 : Provide custom owner password; default is %s\n"
878
        "  --owner-well-known:\n"
879
        "                 : Use an owner password of 20 zero bytes\n"
880
        "  --srkpass <password>\n"
881
        "                 : Provide custom SRK password; default is %s\n"
882
        "  --srk-well-known:\n"
883
        "                 : Use an SRK password of 20 zero bytes\n"
884
        "--create-ek-cert : Create an EK certificate; this implies --createek\n"
885
        "\n"
886
        "--create-platform-cert\n"
887
        "                 : Create a platform certificate; this implies --create-ek-cert\n"
888
        "\n"
889
        "--create-spk     : Create storage primary key; this requires --tpm2\n"
890
        "\n"
891
        "--lock-nvram     : Lock NVRAM access\n"
892
        "\n"
893
        "--display        : At the end display as much info as possible about the\n"
894
        "                   configuration of the TPM\n"
895
        "\n"
896
        "--config <config file>\n"
897
        "                 : Path to configuration file; default is %s\n"
898
        "\n"
899
        "--logfile <logfile>\n"
900
        "                 : Path to log file; default is logging to stderr\n"
901
        "\n"
902
        "--keyfile <keyfile>\n"
903
        "                 : Path to a key file containing the encryption key for the\n"
904
        "                   TPM to encrypt its persistent state with. The content\n"
905
        "                   must be a 32 hex digit number representing a 128bit AES key.\n"
906
        "                   This parameter will be passed to the TPM using\n"
907
        "                   '--key file=<file>'.\n"
908
        "\n"
909
        "--keyfile-fd <fd>: Like --keyfile but a file descriptor is given to read the\n"
910
        "                   encryption key from.\n"
911
        "\n"
912
        "--pwdfile <pwdfile>\n"
913
        "                 : Path to a file containing a passphrase from which the\n"
914
        "                   TPM will derive the 128bit AES key. The passphrase can be\n"
915
        "                   32 bytes long.\n"
916
        "                   This parameter will be passed to the TPM using\n"
917
        "                   '--key pwdfile=<file>'.\n"
918
        "\n"
919
        "--pwdfile-fd <fd>: Like --pwdfile but a file descriptor is given to to read\n"
920
        "                   the passphrase from.\n"
921
        "\n"
922
        "--cipher <cipher>: The cipher to use; either aes-128-cbc or aes-256-cbc;\n"
923
        "                   the default is aes-128-cbc; the same cipher must be\n"
924
        "                   used on the swtpm command line\n"
925
        "\n"
926
        "--overwrite      : Overwrite existing TPM state by re-initializing it; if this\n"
927
        "                   option is not given, this program will return an error if\n"
928
        "                   existing state is detected\n"
929
        "\n"
930
        "--not-overwrite  : Do not overwrite existing TPM state but silently end\n"
931
        "\n"
932
        "--vmid <vm id>   : Unique (VM) identifier to use as common name in certificate\n"
933
        "\n"
934
        "--pcr-banks <banks>\n"
935
        "                 : Set of PCR banks to activate. Provide a comma separated list\n"
936
        "                   like 'sha1,sha256'. '-' to skip and leave all banks active.\n"
937
        "                   Default: %s\n"
938
        "\n"
939
        "--rsa-keysize <keysize>\n"
940
        "                 : The RSA key size of the EK key; 3072 bits may be supported\n"
941
        "                   if libtpms supports it.\n"
942
        "                   Default: %u\n"
943
        "\n"
944
        "--write-ek-cert-files <directory>\n"
945
        "                 : Write EK cert files into the given directory\n"
946
        "\n"
947
        "--tcsd-system-ps-file <file>\n"
948
        "                 : This option is deprecated and has no effect.\n"
949
        "\n"
950
        "--print-capabilities\n"
951
        "                 : Print JSON formatted capabilities added after v0.1 and exit.\n"
952
        "\n"
953
        "--create-config-files [[overwrite][,root]]\n"
954
        "                 : Create swtpm_setup and swtpm-localca config files for a\n"
955
        "                   user account.\n"
956
        "                   overwrite: overwrite any existing files\n"
957
        "                   root: allow to create files under root's home directory\n"
958
        "                   skip-if-exist: if any file exists exit without error\n"
959
        "\n"
960
        "--reconfigure    : Reconfigure an existing swtpm by reusing existing state.\n"
961
        "                   The active PCR banks can be changed but no new keys will\n"
962
        "                   be created.\n"
963
        "\n"
964
        "--version        : Display version and exit\n"
965
        "\n"
966
        "--help,-h        : Display this help screen\n\n",
967
            prgname,
968
            DEFAULT_OWNER_PASSWORD,
969
            DEFAULT_SRK_PASSWORD,
970
            default_config_file,
971
            DEFAULT_PCR_BANKS,
972
            DEFAULT_RSA_KEYSIZE
973
        );
974
}
1✔
975

976
static int get_swtpm_capabilities(gchar **swtpm_prg_l, gboolean is_tpm2,
137✔
977
                                  gchar **standard_output)
978
{
979
    gchar *my_argv[] = { "--print-capabilities", is_tpm2 ? "--tpm2" : NULL, NULL };
137✔
980
    g_autofree gchar *logop = NULL;
274✔
981
    g_autoptr(GError) error = NULL;
137✔
982
    g_autofree gchar **argv = NULL;
137✔
983
    int exit_status = 0;
137✔
984
    gboolean success;
137✔
985
    int ret = 1;
137✔
986

987
    argv = concat_arrays(swtpm_prg_l, my_argv, FALSE);
137✔
988

989
    if (gl_LOGFILE != NULL) {
137✔
990
        logop = g_strdup_printf("file=%s", gl_LOGFILE);
31✔
991
        argv = concat_arrays(argv, (gchar*[]){"--log", logop, NULL}, TRUE);
31✔
992
    }
993

994
    success = g_spawn_sync(NULL, argv, NULL, G_SPAWN_STDERR_TO_DEV_NULL, NULL, NULL,
137✔
995
                           standard_output, NULL, &exit_status, &error);
996
    if (!success) {
137✔
997
        logerr(gl_LOGFILE, "Could not start swtpm '%s': %s\n", swtpm_prg_l[0], error->message);
×
998
        goto error;
×
999
    }
1000
    ret = 0;
1001

1002
error:
137✔
1003
    return ret;
137✔
1004
}
1005

1006
static int get_supported_tpm_versions(gchar **swtpm_prg_l, gboolean *swtpm_has_tpm12,
84✔
1007
                                      gboolean *swtpm_has_tpm2)
1008
{
1009
    g_autofree gchar *standard_output = NULL;
168✔
1010
    int ret;
84✔
1011

1012
    ret = get_swtpm_capabilities(swtpm_prg_l, FALSE, &standard_output);
84✔
1013
    if (ret)
84✔
1014
        return ret;
1015

1016
    *swtpm_has_tpm12 = g_strstr_len(standard_output, -1, "\"tpm-1.2\"") != NULL;
84✔
1017
    *swtpm_has_tpm2 = g_strstr_len(standard_output, -1, "\"tpm-2.0\"") != NULL;
84✔
1018

1019
    return 0;
84✔
1020
}
1021

1022
/* Get the support RSA key sizes.
1023
 *  This function returns an array of ints like the following
1024
 *  - [ 1024, 2048, 3072 ]
1025
 *  - [] (empty array, indicating only 2048 bit RSA keys are supported)
1026
 */
1027
static int get_rsa_keysizes(unsigned long flags, gchar **swtpm_prg_l,
79✔
1028
                            unsigned int **keysizes, size_t *n_keysizes)
1029
{
1030
    g_autofree gchar *standard_output = NULL;
158✔
1031
    const gchar *needle = "\"rsa-keysize-";
79✔
1032
    unsigned int keysize;
79✔
1033
    int ret = 1;
79✔
1034
    char *p;
79✔
1035
    int n;
79✔
1036

1037
    *n_keysizes = 0;
79✔
1038

1039
    if (flags & SETUP_TPM2_F) {
79✔
1040
        ret = get_swtpm_capabilities(swtpm_prg_l, TRUE, &standard_output);
53✔
1041
        if (ret)
53✔
1042
            goto error;
×
1043

1044
        p = standard_output;
53✔
1045
        /* A crude way of parsing the json output just looking for "rsa-keysize-%u" */
1046
        while ((p = g_strstr_len(p, -1, needle)) != NULL) {
212✔
1047
            p += strlen(needle);
159✔
1048
            n = sscanf(p, "%u\"", &keysize);
159✔
1049
            if (n == 1) {
159✔
1050
                *keysizes = g_realloc(*keysizes, (*n_keysizes + 1) * sizeof(unsigned int));
159✔
1051
                (*keysizes)[*n_keysizes] = keysize;
159✔
1052
                (*n_keysizes)++;
159✔
1053
            }
1054
        }
1055
    }
1056
    ret = 0;
1057

1058
error:
79✔
1059
    return ret;
79✔
1060
}
1061

1062
/* Return the RSA key size capabilities in a NULL-terminated array */
1063
static int get_rsa_keysize_caps(unsigned long flags, gchar **swtpm_prg_l,
6✔
1064
                                gchar ***keysize_strs)
1065
{
1066
    unsigned int *keysizes = NULL;
6✔
1067
    size_t n_keysizes = 0;
6✔
1068
    size_t i, j;
6✔
1069
    int ret = get_rsa_keysizes(flags, swtpm_prg_l, &keysizes, &n_keysizes);
6✔
1070
    if (ret)
6✔
1071
        return ret;
1072

1073
    *keysize_strs = g_malloc0(sizeof(char *) * (n_keysizes + 1));
6✔
1074
    for (i = 0, j = 0; i < n_keysizes; i++) {
24✔
1075
        if (keysizes[i] >= 2048)
18✔
1076
            (*keysize_strs)[j++] = g_strdup_printf("tpm2-rsa-keysize-%u", keysizes[i]);
12✔
1077
    }
1078

1079
    g_free(keysizes);
6✔
1080

1081
    return 0;
6✔
1082
}
1083

1084
/* Print the JSON object of swtpm_setup's capabilities */
1085
static int print_capabilities(char **swtpm_prg_l, gboolean swtpm_has_tpm12,
6✔
1086
                              gboolean swtpm_has_tpm2)
1087
{
1088
    g_autofree gchar *param = g_strdup("");
6✔
1089
    gchar **keysize_strs = NULL;
6✔
1090
    gchar *tmp;
6✔
1091
    size_t i;
6✔
1092
    int ret = 0;
6✔
1093

1094
    ret = get_rsa_keysize_caps(SETUP_TPM2_F, swtpm_prg_l, &keysize_strs);
6✔
1095
    if (ret)
6✔
1096
        return 1;
1097

1098
    for (i = 0; keysize_strs[i] != NULL; i++) {
18✔
1099
        tmp = g_strdup_printf("%s, \"%s\"", param, keysize_strs[i]);
12✔
1100
        g_free(param);
12✔
1101
        param = tmp;
12✔
1102
    }
1103

1104
    printf("{ \"type\": \"swtpm_setup\", "
6✔
1105
           "\"features\": [ %s%s\"cmdarg-keyfile-fd\", \"cmdarg-pwdfile-fd\", \"tpm12-not-need-root\""
1106
           ", \"cmdarg-write-ek-cert-files\", \"cmdarg-create-config-files\""
1107
           ", \"cmdarg-reconfigure-pcr-banks\""
1108
           "%s ], "
1109
           "\"version\": \"" VERSION "\" "
1110
           "}\n",
1111
           swtpm_has_tpm12 ? "\"tpm-1.2\", " : "",
1112
           swtpm_has_tpm2  ? "\"tpm-2.0\", " : "",
1113
           param);
1114

1115
    g_strfreev(keysize_strs);
6✔
1116

1117
    return 0;
6✔
1118
}
1119

1120
static int change_process_owner(const char *user)
1121
{
1122
    char *endptr;
×
1123
    unsigned long long uid = strtoull(user, &endptr, 10);
×
1124
    gid_t gid;
×
1125
    struct passwd *passwd;
×
1126
    int ret = 1;
×
1127

1128
    if (*endptr != '\0') {
×
1129
        /* assuming a name */
1130
        passwd = getpwnam(user);
×
1131
        if (passwd == NULL) {
×
1132
            logerr(gl_LOGFILE, "Error: User '%s' does not exist.\n", user);
×
1133
            goto error;
×
1134
        }
1135

1136
        if (initgroups(passwd->pw_name, passwd->pw_gid) != 0) {
×
1137
            logerr(gl_LOGFILE, "Error: initgroups() failed: %s\n", strerror(errno));
×
1138
            goto error;
×
1139
        }
1140

1141
        gid = passwd->pw_gid;
×
1142
        uid = passwd->pw_uid;
×
1143
    } else {
1144
        if (uid > 0xffffffff) {
×
1145
            logerr(gl_LOGFILE, "Error: uid %s outside valid range.\n", user);
×
1146
            goto error;
×
1147
        }
1148
        gid = (gid_t)uid;
×
1149
    }
1150

1151
    if (setgid(gid) != 0) {
×
1152
        logerr(gl_LOGFILE, "Error: setgid(%d) failed: %s\n", gid, strerror(errno));
×
1153
        goto error;
×
1154
    }
1155

1156
    if (setuid(uid) != 0) {
×
1157
        logerr(gl_LOGFILE, "Error: setuid(%d) failed: %s\n", uid, strerror(errno));
×
1158
        goto error;
×
1159
    }
1160

1161
    ret = 0;
1162

1163
error:
×
1164
    return ret;
×
1165
}
1166

1167
static int handle_create_config_files(const char *optarg)
1168
{
1169
    g_auto(GStrv) tokens = NULL;
×
1170
    gboolean overwrite = FALSE;
×
1171
    gboolean root_flag = FALSE;
×
1172
    gboolean skip_if_exist = FALSE;
×
1173

1174
    if (optarg) {
×
1175
        tokens = g_strsplit_set(optarg, ", ", -1);
×
1176
        overwrite = g_strv_contains((const gchar **)tokens, "overwrite");
×
1177
        root_flag = g_strv_contains((const gchar **)tokens, "root");
×
1178
        skip_if_exist = g_strv_contains((const gchar **)tokens, "skip-if-exist");
×
1179
        if (overwrite && skip_if_exist) {
×
1180
            fprintf(stderr, "Error: overwrite and skip-if-exist cannot both be used\n");
×
1181
            return 1;
×
1182
        }
1183
    }
1184

1185
    return create_config_files(overwrite, root_flag, skip_if_exist);
×
1186
}
1187

1188
int main(int argc, char *argv[])
97✔
1189
{
1190
    int opt, option_index = 0;
97✔
1191
    static const struct option long_options[] = {
97✔
1192
        {"tpm-state", required_argument, NULL, 't'},
1193
        {"tpmstate", required_argument, NULL, 't'}, /* alias for tpm-state */
1194
        {"tpm", required_argument, NULL, 'T'},
1195
        {"swtpm_ioctl", required_argument, NULL, '_'},
1196
        {"tpm2", no_argument, NULL, '2'},
1197
        {"ecc", no_argument, NULL, 'e'},
1198
        {"createek", no_argument, NULL, 'c'},
1199
        {"create-spk", no_argument, NULL, 'C'},
1200
        {"take-ownership", no_argument, NULL, 'o'},
1201
        {"ownerpass", required_argument, NULL, 'O'},
1202
        {"owner-well-known", no_argument, NULL, 'w'},
1203
        {"srkpass", required_argument, NULL, 'S'},
1204
        {"srk-well-known", no_argument, NULL, 's'},
1205
        {"create-ek-cert", no_argument, NULL, 'E'},
1206
        {"create-platform-cert", no_argument, NULL, 'P'},
1207
        {"lock-nvram", no_argument, NULL, 'L'},
1208
        {"display", no_argument, NULL, 'i'},
1209
        {"config", required_argument, NULL, 'f'},
1210
        {"vmid", required_argument, NULL, 'm'},
1211
        {"keyfile", required_argument, NULL, 'x'},
1212
        {"keyfile-fd", required_argument, NULL, 'X'},
1213
        {"pwdfile", required_argument, NULL, 'k'},
1214
        {"pwdfile-fd", required_argument, NULL, 'K'},
1215
        {"cipher", required_argument, NULL, 'p'},
1216
        {"runas", required_argument, NULL, 'r'},
1217
        {"logfile", required_argument, NULL, 'l'},
1218
        {"overwrite", no_argument, NULL, 'v'},
1219
        {"not-overwrite", no_argument, NULL, 'V'},
1220
        {"allow-signing", no_argument, NULL, 'a'},
1221
        {"decryption", no_argument, NULL, 'd'},
1222
        {"pcr-banks", required_argument, NULL, 'b'},
1223
        {"rsa-keysize", required_argument, NULL, 'A'},
1224
        {"write-ek-cert-files", required_argument, NULL, '3'},
1225
        {"create-config-files", optional_argument, NULL, 'u'},
1226
        {"tcsd-system-ps-file", required_argument, NULL, 'F'},
1227
        {"version", no_argument, NULL, '1'},
1228
        {"print-capabilities", no_argument, NULL, 'y'},
1229
        {"reconfigure", no_argument, NULL, 'R'},
1230
        {"help", no_argument, NULL, 'h'},
1231
        {NULL, 0, NULL, 0}
1232
    };
1233
    unsigned long flags = 0;
97✔
1234
    g_autofree gchar *swtpm_prg = NULL;
97✔
1235
    g_autofree gchar *tpm_state_path = NULL;
97✔
1236
    struct swtpm_backend_ops *backend_ops = &swtpm_backend_dir;
97✔
1237
    void *backend_state = NULL;
97✔
1238
    g_autofree gchar *config_file = NULL;
97✔
1239
    g_autofree gchar *ownerpass = NULL;
97✔
1240
    gboolean got_ownerpass = FALSE;
97✔
1241
    g_autofree gchar *srkpass = NULL;
97✔
1242
    gboolean got_srkpass = FALSE;
97✔
1243
    g_autofree gchar *vmid = NULL;
97✔
1244
    g_autofree gchar *pcr_banks = NULL;
97✔
1245
    gboolean printcapabilities = FALSE;
97✔
1246
    g_autofree gchar *keyfile = NULL;
97✔
1247
    long int keyfile_fd = -1;
97✔
1248
    g_autofree gchar *pwdfile = NULL;
97✔
1249
    long int pwdfile_fd = -1;
97✔
1250
    g_autofree gchar *cipher = g_strdup("aes-128-cbc");
194✔
1251
    g_autofree gchar *rsa_keysize_str = g_strdup_printf("%d", DEFAULT_RSA_KEYSIZE);
194✔
1252
    unsigned int rsa_keysize;
97✔
1253
    g_autofree gchar *swtpm_keyopt = NULL;
97✔
1254
    g_autofree gchar *runas = NULL;
97✔
1255
    g_autofree gchar *certsdir = NULL;
97✔
1256
    g_autofree gchar *user_certsdir = NULL;
97✔
1257
    gchar *tmp;
97✔
1258
    gchar **swtpm_prg_l = NULL;
97✔
1259
    gchar **tmp_l = NULL;
97✔
1260
    size_t i, n;
97✔
1261
    struct stat statbuf;
97✔
1262
    const struct passwd *curr_user;
97✔
1263
    struct group *curr_grp;
97✔
1264
    char *endptr;
97✔
1265
    gboolean swtpm_has_tpm12 = FALSE;
97✔
1266
    gboolean swtpm_has_tpm2 = FALSE;
97✔
1267
    int fds_to_pass[1] = { -1 };
97✔
1268
    unsigned n_fds_to_pass = 0;
97✔
1269
    char tmpbuffer[200];
97✔
1270
    time_t now;
97✔
1271
    struct tm *tm;
97✔
1272
    int ret = 1;
97✔
1273
    g_autoptr(GError) error = NULL;
97✔
1274

1275
    setvbuf(stdout, 0, _IONBF, 0);
97✔
1276

1277
    if (init(&config_file) < 0)
97✔
1278
        goto error;
×
1279

1280
    swtpm_prg = g_find_program_in_path("swtpm");
97✔
1281
    if (swtpm_prg) {
97✔
1282
        tmp = g_strconcat(swtpm_prg, " socket", NULL);
63✔
1283
        g_free(swtpm_prg);
63✔
1284
        swtpm_prg = tmp;
63✔
1285
    }
1286

1287
    while ((opt = getopt_long(argc, argv, "h?",
1,682✔
1288
                              long_options, &option_index)) != -1) {
841✔
1289
        switch (opt) {
746✔
1290
        case 't': /* --tpmstate, --tpm-state */
88✔
1291
            g_free(tpm_state_path);
88✔
1292
            if (strncmp(optarg, "dir://", 6) == 0) {
88✔
1293
                tpm_state_path = g_strdup(optarg);
10✔
1294
            } else if (strncmp(optarg, "file://", 7) == 0) {
78✔
1295
                tpm_state_path = g_strdup(optarg);
3✔
1296
                backend_ops = &swtpm_backend_file;
3✔
1297
            } else {
1298
                /* always prefix with dir:// so we can pass verbatim to swtpm */
1299
                tpm_state_path = g_strconcat("dir://", optarg, NULL);
75✔
1300
            }
1301
            break;
1302
        case 'T': /* --tpm */
79✔
1303
            g_free(swtpm_prg);
79✔
1304
            swtpm_prg = g_strdup(optarg);
79✔
1305
            break;
79✔
1306
        case '_': /* --swtpm_ioctl */
×
1307
            fprintf(stdout, "Warning: --swtpm_ioctl is deprecated and has no effect.");
×
1308
            break;
1309
        case '2': /* --tpm2 */
57✔
1310
            flags |= SETUP_TPM2_F;
57✔
1311
            break;
57✔
1312
        case 'e': /* --ecc */
16✔
1313
            flags |= SETUP_TPM2_ECC_F;
16✔
1314
            break;
16✔
1315
        case 'c': /* --createek */
44✔
1316
            flags |= SETUP_CREATE_EK_F;
44✔
1317
            break;
44✔
1318
        case 'C': /* --create-spk */
4✔
1319
            flags |= SETUP_CREATE_SPK_F;
4✔
1320
            break;
4✔
1321
        case 'o': /* --take-ownership */
10✔
1322
            flags |= SETUP_CREATE_EK_F | SETUP_TAKEOWN_F;
10✔
1323
            break;
10✔
1324
        case 'O': /* --ownerpass */
2✔
1325
            g_free(ownerpass);
2✔
1326
            ownerpass = g_strdup(optarg);
2✔
1327
            got_ownerpass = TRUE;
2✔
1328
            break;
2✔
1329
        case 'w': /* --owner-well-known */
2✔
1330
            flags |= SETUP_OWNERPASS_ZEROS_F;
2✔
1331
            got_ownerpass = TRUE;
2✔
1332
            break;
2✔
1333
        case 'S': /* --srk-pass */
2✔
1334
            g_free(srkpass);
2✔
1335
            srkpass = g_strdup(optarg);
2✔
1336
            got_srkpass = TRUE;
2✔
1337
            break;
2✔
1338
        case 's': /* --srk-well-known */
2✔
1339
            flags |= SETUP_SRKPASS_ZEROS_F;
2✔
1340
            got_srkpass = TRUE;
2✔
1341
            break;
2✔
1342
        case 'E': /* --create-ek-cert */
42✔
1343
            flags |= SETUP_CREATE_EK_F | SETUP_EK_CERT_F;
42✔
1344
            break;
42✔
1345
        case 'P': /* --create-platform-cert */
40✔
1346
            flags |= SETUP_CREATE_EK_F | SETUP_PLATFORM_CERT_F;
40✔
1347
            break;
40✔
1348
        case 'L': /* --lock-nvram */
15✔
1349
            flags |= SETUP_LOCK_NVRAM_F;
15✔
1350
            break;
15✔
1351
        case 'i': /* --display */
36✔
1352
            flags |= SETUP_DISPLAY_RESULTS_F;
36✔
1353
            break;
36✔
1354
        case 'f': /* --config */
115✔
1355
            g_free(config_file);
115✔
1356
            config_file = g_strdup(optarg);
115✔
1357
            break;
115✔
1358
        case 'm': /* --vmid */
36✔
1359
            g_free(vmid);
36✔
1360
            vmid = g_strdup(optarg);
36✔
1361
            break;
36✔
1362
        case 'x': /* --keyfile */
11✔
1363
            g_free(keyfile);
11✔
1364
            keyfile = g_strdup(optarg);
11✔
1365
            break;
11✔
1366
        case 'X': /* --pwdfile-fd' */
2✔
1367
            keyfile_fd = strtoull(optarg, &endptr, 10);
2✔
1368
            if (*endptr != '\0' && keyfile_fd >= INT_MAX) {
2✔
1369
                fprintf(stderr, "Invalid file descriptor '%s'\n", optarg);
×
1370
                goto error;
×
1371
            }
1372
            break;
1373
        case 'k': /* --pwdfile */
15✔
1374
            g_free(pwdfile);
15✔
1375
            pwdfile = g_strdup(optarg);
15✔
1376
            break;
15✔
1377
        case 'K': /* --pwdfile-fd' */
2✔
1378
            pwdfile_fd = strtoull(optarg, &endptr, 10);
2✔
1379
            if (*endptr != '\0' || pwdfile_fd >= INT_MAX) {
2✔
1380
                fprintf(stderr, "Invalid file descriptor '%s'\n", optarg);
×
1381
                goto error;
×
1382
            }
1383
            break;
1384
        case 'p': /* --cipher */
13✔
1385
            g_free(cipher);
13✔
1386
            cipher = g_strdup(optarg);
13✔
1387
            break;
13✔
1388
        case 'r': /* --runas */
×
1389
            g_free(runas);
×
1390
            runas = g_strdup(optarg);
×
1391
            break;
×
1392
        case 'l': /* --logfile */
20✔
1393
            g_free(gl_LOGFILE);
20✔
1394
            gl_LOGFILE = g_strdup(optarg);
20✔
1395
            break;
20✔
1396
        case 'v': /* --overwrite */
18✔
1397
            flags |= SETUP_STATE_OVERWRITE_F;
18✔
1398
            break;
18✔
1399
        case 'V': /* --not-overwrite */
3✔
1400
            flags |= SETUP_STATE_NOT_OVERWRITE_F;
3✔
1401
            break;
3✔
1402
        case 'a': /* --allow-signing */
23✔
1403
            flags |= SETUP_ALLOW_SIGNING_F;
23✔
1404
            break;
23✔
1405
        case 'd': /* --decryption */
7✔
1406
            flags |= SETUP_DECRYPTION_F;
7✔
1407
            break;
7✔
1408
        case 'b': /* --pcr-banks */
7✔
1409
            tmp = g_strconcat(pcr_banks ? pcr_banks: "",
21✔
1410
                              pcr_banks ? "," : "", g_strstrip(optarg), NULL);
1411
            g_free(pcr_banks);
7✔
1412
            pcr_banks = tmp;
7✔
1413
            break;
7✔
1414
        case 'A': /* --rsa-keysize */
14✔
1415
            g_free(rsa_keysize_str);
14✔
1416
            rsa_keysize_str = strdup(optarg);
14✔
1417
            break;
14✔
1418
        case '3': /* --write-ek-cert-files */
5✔
1419
            g_free(user_certsdir);
5✔
1420
            user_certsdir = g_strdup(optarg);
5✔
1421
            flags |= SETUP_WRITE_EK_CERT_FILES_F;
5✔
1422
            break;
5✔
1423
        case 'u':
×
1424
            if (optarg == NULL && optind < argc && argv[optind][0] != '0')
×
1425
                optarg = argv[optind++];
×
1426
            ret = handle_create_config_files(optarg);
×
1427
            goto out;
×
1428
        case 'F': /* --tcsd-system-ps-file */
1429
            printf("Warning: --tcsd-system-ps-file is deprecated and has no effect.");
841✔
1430
            break;
1431
        case '1': /* --version */
1✔
1432
            versioninfo();
1✔
1433
            ret = 0;
1✔
1434
            goto out;
1✔
1435
        case 'y': /* --print-capabilities */
1436
            printcapabilities = TRUE;
1437
            break;
1438
        case 'R': /* --reconfigure */
8✔
1439
            flags |= SETUP_RECONFIGURE_F;
8✔
1440
            break;
8✔
1441
        case '?':
1✔
1442
        case 'h': /* --help */
1443
            usage(argv[0], config_file);
1✔
1444
            if (opt == 'h')
1✔
1445
                ret = 0;
1✔
1446
            goto out;
1✔
1447
        default:
×
1448
            fprintf(stderr, "Unknown option code %d\n", opt);
×
1449
            usage(argv[0], config_file);
×
1450
            goto error;
×
1451
        }
1452
    }
1453

1454
    if (swtpm_prg == NULL) {
95✔
1455
        logerr(gl_LOGFILE,
11✔
1456
               "Default TPM 'swtpm' could not be found and was not provided using --tpm.\n");
1457
        goto error;
11✔
1458
    }
1459

1460
    swtpm_prg_l = split_cmdline(swtpm_prg);
84✔
1461
    tmp = g_find_program_in_path(swtpm_prg_l[0]);
84✔
1462
    if (!tmp) {
84✔
1463
        logerr(gl_LOGFILE, "swtpm at %s is not an executable.\n", swtpm_prg_l[0]);
×
1464
        goto error;
×
1465
    }
1466
    g_free(tmp);
84✔
1467

1468

1469
    ret = get_supported_tpm_versions(swtpm_prg_l, &swtpm_has_tpm12, &swtpm_has_tpm2);
84✔
1470
    if (ret != 0)
84✔
1471
        goto error;
×
1472

1473
    if (printcapabilities) {
84✔
1474
        ret = print_capabilities(swtpm_prg_l, swtpm_has_tpm12, swtpm_has_tpm2);
6✔
1475
        goto out;
6✔
1476
    }
1477

1478
    if ((flags & SETUP_TPM2_F) != 0 && !swtpm_has_tpm2) {
78✔
1479
        logerr(gl_LOGFILE, "swtpm at %s does not support TPM 2\n", swtpm_prg_l[0]);
×
1480
        goto error;
×
1481
    } else if ((flags & SETUP_TPM2_F) == 0 && !swtpm_has_tpm12){
78✔
1482
        logerr(gl_LOGFILE, "swtpm at %s does not support TPM 1.2\n", swtpm_prg_l[0]);
×
1483
        goto error;
×
1484
    }
1485

1486
    if (runas) {
78✔
1487
        ret = change_process_owner(runas);
×
1488
        if (ret != 0)
×
1489
            goto error;
×
1490
    }
1491

1492
    if (!got_ownerpass)
78✔
1493
        ownerpass = g_strdup(DEFAULT_OWNER_PASSWORD);
74✔
1494
    if (!got_srkpass)
78✔
1495
        srkpass = g_strdup(DEFAULT_SRK_PASSWORD);
74✔
1496

1497
    if (gl_LOGFILE != NULL) {
78✔
1498
        FILE *tmpfile;
20✔
1499
        if (stat(gl_LOGFILE, &statbuf) == 0 &&
20✔
1500
            (statbuf.st_mode & S_IFMT) == S_IFLNK) {
20✔
1501
            fprintf(stderr, "Logfile must not be a symlink.\n");
×
1502
            goto error;
×
1503
        }
1504
        tmpfile = fopen(gl_LOGFILE, "a");
20✔
1505
        if (tmpfile == NULL) {
20✔
1506
            fprintf(stderr, "Cannot write to logfile %s.\n", gl_LOGFILE);
×
1507
            goto error;
×
1508
        }
1509
        fclose(tmpfile);
20✔
1510
    }
1511

1512
    curr_user = getpwuid(getuid());
78✔
1513

1514
    // Check tpm_state_path directory and access rights
1515
    if (tpm_state_path == NULL) {
78✔
1516
        logerr(gl_LOGFILE, "--tpm-state must be provided\n");
×
1517
        goto error;
×
1518
    }
1519

1520
    backend_state = backend_ops->parse_backend(tpm_state_path);
78✔
1521
    if (!backend_state)
78✔
1522
        goto error;
×
1523

1524
    if (backend_ops->check_access(backend_state, R_OK|W_OK, curr_user) != 0)
78✔
1525
        goto error;
×
1526

1527
    if ((flags & SETUP_WRITE_EK_CERT_FILES_F)) {
78✔
1528
        if (check_directory_access(user_certsdir, W_OK, curr_user) != 0)
5✔
1529
            goto error;
×
1530
    }
1531

1532
    if (flags & SETUP_TPM2_F) {
78✔
1533
        if (flags & SETUP_TAKEOWN_F) {
49✔
1534
            logerr(gl_LOGFILE, "Taking ownership is not supported for TPM 2.\n");
×
1535
            goto error;
×
1536
        }
1537
    } else {
1538
        if (flags & SETUP_TPM2_ECC_F) {
29✔
1539
            logerr(gl_LOGFILE, "--ecc requires --tpm2.\n");
×
1540
            goto error;
×
1541
        }
1542
        if (flags & SETUP_CREATE_SPK_F) {
29✔
1543
            logerr(gl_LOGFILE, "--create-spk requires --tpm2.\n");
×
1544
            goto error;
×
1545
        }
1546
        if (flags & SETUP_RECONFIGURE_F) {
29✔
1547
            logerr(gl_LOGFILE, "--reconfigure requires --tpm2.\n");
×
1548
            goto error;
×
1549
        }
1550
        if (flags & SETUP_ALLOW_SIGNING_F) {
29✔
1551
            logerr(gl_LOGFILE, "--allow-signing requires --tpm2.\n");
×
1552
            goto error;
×
1553
        }
1554
        if (flags & SETUP_DECRYPTION_F) {
29✔
1555
            logerr(gl_LOGFILE, "--decryption requires --tpm2.\n");
×
1556
            goto error;
×
1557
        }
1558
        if (pcr_banks) {
29✔
1559
            logerr(gl_LOGFILE, "--pcr-banks requires --tpm2.\n");
×
1560
            goto error;
×
1561
        }
1562
    }
1563

1564
    if (!(flags & SETUP_RECONFIGURE_F)) {
78✔
1565
        ret = check_state_overwrite(swtpm_prg_l, flags, tpm_state_path);
72✔
1566
        if (ret == 1) {
72✔
1567
            goto error;
3✔
1568
        } else if (ret == 2) {
69✔
1569
            ret = 0;
2✔
1570
            goto out;
2✔
1571
        }
1572

1573
        ret = backend_ops->delete_state(backend_state);
67✔
1574
        if (ret != 0)
67✔
1575
            goto error;
×
1576
    }
1577

1578
    if (access(config_file, R_OK) != 0) {
73✔
1579
        logerr(gl_LOGFILE, "User %s cannot read config file %s.\n",
×
1580
               curr_user ? curr_user->pw_name : "<unknown>", config_file);
1581
        goto error;
×
1582
    }
1583

1584
    /* check pcr_banks; read from config file if not given */
1585
    tmp_l = g_strsplit(pcr_banks ? pcr_banks : "", ",", -1);
73✔
1586
    for (i = 0, n = 0; tmp_l[i]; i++) {
158✔
1587
        g_strstrip(tmp_l[i]);
12✔
1588
        n += strlen(tmp_l[i]);
12✔
1589
    }
1590
    g_strfreev(tmp_l);
73✔
1591
    if (n == 0) {
73✔
1592
        g_free(pcr_banks);
67✔
1593
        pcr_banks = get_default_pcr_banks(config_file);
67✔
1594
    }
1595

1596
    if (cipher != NULL) {
73✔
1597
        if (strcmp(cipher, "aes-128-cbc") != 0 &&
73✔
1598
            strcmp(cipher, "aes-cbc") != 0 &&
12✔
1599
            strcmp(cipher, "aes-256-cbc") != 0) {
12✔
1600
            logerr(gl_LOGFILE, "Unsupported cipher %s.\n", cipher);
×
1601
            goto error;
×
1602
        }
1603
        tmp = g_strdup_printf(",mode=%s", cipher);
73✔
1604
        g_free(cipher);
73✔
1605
        cipher = tmp;
73✔
1606
    }
1607

1608
    if (keyfile != NULL) {
73✔
1609
        if (access(keyfile, R_OK) != 0) {
11✔
1610
            logerr(gl_LOGFILE, "User %s cannot read keyfile %s.\n",
×
1611
                   curr_user ? curr_user->pw_name : "<unknown>", keyfile);
1612
            goto error;
×
1613
        }
1614
        swtpm_keyopt = g_strdup_printf("file=%s%s", keyfile, cipher);
11✔
1615
        logit(gl_LOGFILE, "  The TPM's state will be encrypted with a provided key.\n");
11✔
1616
    } else if (pwdfile != NULL) {
62✔
1617
        if (access(pwdfile, R_OK) != 0) {
15✔
1618
            logerr(gl_LOGFILE, "User %s cannot read passphrase file %s.\n",
×
1619
                   curr_user ? curr_user->pw_name : "<unknown>", pwdfile);
1620
            goto error;
×
1621
        }
1622
        swtpm_keyopt = g_strdup_printf("pwdfile=%s%s", pwdfile, cipher);
15✔
1623
        logit(gl_LOGFILE, "  The TPM's state will be encrypted using a key derived from a passphrase.\n");
15✔
1624
    } else if (keyfile_fd >= 0) {
47✔
1625
        fds_to_pass[n_fds_to_pass++] = keyfile_fd;
2✔
1626
        swtpm_keyopt = g_strdup_printf("fd=%ld%s", keyfile_fd, cipher);
2✔
1627
        logit(gl_LOGFILE, "  The TPM's state will be encrypted with a provided key (fd).\n");
2✔
1628
    } else if (pwdfile_fd >= 0) {
45✔
1629
        fds_to_pass[n_fds_to_pass++] = pwdfile_fd;
2✔
1630
        swtpm_keyopt = g_strdup_printf("pwdfd=%ld%s", pwdfile_fd, cipher);
2✔
1631
        logit(gl_LOGFILE, "  The TPM's state will be encrypted using a key derived from a passphrase (fd).\n");
2✔
1632
    }
1633

1634
    if (strcmp(rsa_keysize_str, "max") == 0) {
73✔
1635
        unsigned int *keysizes = NULL;
×
1636
        size_t n_keysizes;
×
1637

1638
        ret = get_rsa_keysizes(flags, swtpm_prg_l, &keysizes, &n_keysizes);
×
1639
        if (ret)
×
1640
            goto error;
×
1641
        g_free(rsa_keysize_str);
×
1642
        if (n_keysizes > 0) {
×
1643
            /* last one is the biggest one */
1644
            rsa_keysize_str = g_strdup_printf("%u", keysizes[n_keysizes - 1]);
×
1645
        } else {
1646
            rsa_keysize_str = g_strdup("2048");
×
1647
        }
1648
        g_free(keysizes);
×
1649
    }
1650
    if (strcmp(rsa_keysize_str, "2048") == 0 || strcmp(rsa_keysize_str, "3072") == 0) {
73✔
1651
        unsigned int *keysizes = NULL;
73✔
1652
        size_t n_keysizes;
73✔
1653
        gboolean found = FALSE;
73✔
1654

1655
        ret = get_rsa_keysizes(flags, swtpm_prg_l, &keysizes, &n_keysizes);
73✔
1656
        if (ret)
73✔
1657
            goto error;
×
1658

1659
        rsa_keysize = strtoull(rsa_keysize_str, NULL, 10);
73✔
1660
        for (i = 0; i < n_keysizes && found == FALSE; i++)
179✔
1661
            found = (keysizes[i] == rsa_keysize);
106✔
1662
        if (!found && rsa_keysize != 2048) {
73✔
1663
            logerr(gl_LOGFILE, "%u bit RSA keys are not supported by libtpms.\n", rsa_keysize);
×
1664
            goto error;
×
1665
        }
1666
        g_free(keysizes);
73✔
1667
    } else {
1668
        logit(gl_LOGFILE, "Unsupported RSA key size %s.\n", rsa_keysize_str);
×
1669
        goto error;
×
1670
    }
1671

1672
    if (flags & SETUP_RECONFIGURE_F) {
73✔
1673
        if (flags & (SETUP_CREATE_EK_F | SETUP_EK_CERT_F | SETUP_PLATFORM_CERT_F)) {
6✔
1674
            logerr(gl_LOGFILE, "Reconfiguration is not supported with creation of EK or certificates\n");
×
1675
            goto error;
×
1676
        }
1677
    }
1678

1679
    now = time(NULL);
73✔
1680
    tm = localtime(&now);
73✔
1681
    if (strftime(tmpbuffer, sizeof(tmpbuffer), "%a %d %h %Y %I:%M:%S %p %Z", tm) == 0) {
73✔
1682
        logerr(gl_LOGFILE, "Could not format time/date string.\n");
×
1683
        goto error;
×
1684
    }
1685
    curr_grp = getgrgid(getgid());
73✔
1686
    logit(gl_LOGFILE, "Starting vTPM %s as %s:%s @ %s\n",
140✔
1687
          flags & SETUP_RECONFIGURE_F ? "reconfiguration" : "manufacturing",
1688
          curr_user ? curr_user->pw_name : "<unknown>",
1689
          curr_grp ? curr_grp->gr_name : "<unknown>",
1690
          tmpbuffer);
1691

1692
    if (flags & (SETUP_EK_CERT_F | SETUP_PLATFORM_CERT_F)) {
73✔
1693
        certsdir = g_dir_make_tmp("swtpm_setup.certs.XXXXXX", &error);
41✔
1694
        if (certsdir == NULL) {
41✔
1695
            logerr(gl_LOGFILE, "Could not create temporary directory for certs: %s\n",
×
1696
                   error->message);
×
1697
            goto error;
×
1698
        }
1699
    }
1700

1701
    if ((flags & SETUP_TPM2_F) == 0) {
73✔
1702
        ret = init_tpm(flags, swtpm_prg_l, config_file, tpm_state_path, ownerpass, srkpass, vmid,
26✔
1703
                       swtpm_keyopt, fds_to_pass, n_fds_to_pass, certsdir, user_certsdir);
1704
    } else {
1705
        ret = init_tpm2(flags, swtpm_prg_l, config_file, tpm_state_path, vmid, pcr_banks,
47✔
1706
                       swtpm_keyopt, fds_to_pass, n_fds_to_pass, rsa_keysize, certsdir,
1707
                       user_certsdir);
1708
    }
1709

1710
    if (ret == 0) {
73✔
1711
        logit(gl_LOGFILE, "Successfully authored TPM state.\n");
73✔
1712
    } else {
1713
        logerr(gl_LOGFILE, "An error occurred. Authoring the TPM state failed.\n");
×
1714
        backend_ops->delete_state(backend_state);
×
1715
    }
1716

1717
    now = time(NULL);
73✔
1718
    tm = localtime(&now);
73✔
1719
    if (strftime(tmpbuffer, sizeof(tmpbuffer), "%a %d %h %Y %I:%M:%S %p %Z", tm) == 0) {
73✔
1720
        logerr(gl_LOGFILE, "Could not format time/date string.\n");
×
1721
        goto error;
×
1722
    }
1723
    logit(gl_LOGFILE, "Ending vTPM manufacturing @ %s\n",
73✔
1724
          tmpbuffer);
1725

1726
out:
97✔
1727
    if (certsdir && g_rmdir(certsdir) != 0)
97✔
1728
        logerr(gl_LOGFILE, "Could not remove temporary directory for certs: %s\n",
×
1729
               strerror(errno));
×
1730

1731
    if (backend_ops && backend_state)
97✔
1732
        backend_ops->free_backend(backend_state);
78✔
1733
    g_strfreev(swtpm_prg_l);
97✔
1734
    g_free(gl_LOGFILE);
97✔
1735

1736
    return ret;
97✔
1737

1738
error:
14✔
1739
    ret = 1;
14✔
1740
    goto out;
14✔
1741
}
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