report: add support for signing reports via varlink backends + make report a varlink service (#42595)
This adds the following: 1. systemd-report gains a new --sign= option, taking a boolean. If true, this makes systemd-report generate + systemd-report upload generate a signed report, instead of a regular one. The signatures are collected from Varlink-based backends. 2. One such backend is added which does a simple Ed21159 based signing scheme. 3. this adds a new metrics source which just reports text files symlinked into a special dir as metrics. This is used to report the Ed21159 public key as metric, by default, if it exists. 4. finally, systemd-report itself is turned into a varlink service. this is useful for example for extracting a report from a system coming in via the varlink/http bridge. I thought a long time about the format of signing of reports. Initially i intended to do this like homed's user record signing, i.e. require normalization of the record, then normalize the record, and write it out in dense form, since the result. Finally insert the resulting hash into the user record itself. People have pointed me to the inherent messiness of signing JSON this way though, as it requires any participant that wishes to sign/authenticate records this way to implement the exact same normalization/formatting rules, and in particular in the area of floating point numbers (of which metrics presumably will have many) this is quite problematic. This signing hence goes a different way. instead of expecting signer+verifier to independently come to the same normalized text form of the json data, let's instead output a JSON-SEQ sequence, where the first object is the report, and any subsequent objects are one signature each. the signatures are supposed to cover the precise binary representation of the first element in the JSON-SEQ stream. (i.e. from the RS to the NL). or in other words: a verifier would receive the JSON-SEQ stream, split it up before each RS. Then it would leave object 1 unparsed for the moment, and parse objects 2…n. It would then authenticate object 1's precise binary representation with objects 2…n. Once that checks out, it would parse object 1, and use it as report.
This commit is contained in:
@@ -1627,6 +1627,9 @@ int digest_and_sign(
|
||||
if (!mdctx)
|
||||
return log_openssl_errors("Failed to create new EVP_MD_CTX");
|
||||
|
||||
/* Note that a NULL 'md' (message digest algorithm) means to sign the provided data directly, without
|
||||
* hashing it first, as long as a suitable signing algorithm is used that supports this, such as
|
||||
* Ed25519 (PureEdDSA). For such algorithms callers may pass an already calculated digest as input. */
|
||||
if (sym_EVP_DigestSignInit(mdctx, NULL, md, NULL, privkey) != 1) {
|
||||
/* Distro security policies often disable support for SHA-1. Let's return a recognizable
|
||||
* error for that case. */
|
||||
|
||||
@@ -241,6 +241,9 @@ shared_sources = files(
|
||||
'varlink-io.systemd.PCRExtend.c',
|
||||
'varlink-io.systemd.PCRLock.c',
|
||||
'varlink-io.systemd.Repart.c',
|
||||
'varlink-io.systemd.Report.c',
|
||||
'varlink-io.systemd.Report.Signer.c',
|
||||
'varlink-io.systemd.Report.Uploader.c',
|
||||
'varlink-io.systemd.Resolve.c',
|
||||
'varlink-io.systemd.Resolve.Hook.c',
|
||||
'varlink-io.systemd.Resolve.Monitor.c',
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "varlink-io.systemd.Report.Signer.h"
|
||||
|
||||
static SD_VARLINK_DEFINE_METHOD(
|
||||
Sign,
|
||||
SD_VARLINK_FIELD_COMMENT("The digest of the data to sign."),
|
||||
SD_VARLINK_DEFINE_INPUT(digest, SD_VARLINK_STRING, 0),
|
||||
SD_VARLINK_FIELD_COMMENT("The digest algorithm used for the digest field above. For now this is always SHA256, but this might be changed eventually."),
|
||||
SD_VARLINK_DEFINE_INPUT(algorithm, SD_VARLINK_STRING, 0),
|
||||
SD_VARLINK_FIELD_COMMENT("An array of signature objects"),
|
||||
SD_VARLINK_DEFINE_OUTPUT(data, SD_VARLINK_OBJECT, SD_VARLINK_ARRAY));
|
||||
|
||||
SD_VARLINK_DEFINE_INTERFACE(
|
||||
io_systemd_Report_Signer,
|
||||
"io.systemd.Report.Signer",
|
||||
SD_VARLINK_INTERFACE_COMMENT("Backend API for signing reports. This interface shall be implemented by services linked into /run/systemd/report.sign/."),
|
||||
SD_VARLINK_SYMBOL_COMMENT("Sign a report, identified by a digest. This may return zero, one or more signatures, as appropriate. For example some backend might have multiple keys or algorithms available, that are appropriate, in which case it can generate multiple signatures."),
|
||||
&vl_method_Sign);
|
||||
@@ -0,0 +1,6 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include "sd-varlink-idl.h"
|
||||
|
||||
extern const sd_varlink_interface vl_interface_io_systemd_Report_Signer;
|
||||
@@ -0,0 +1,17 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "varlink-io.systemd.Report.Uploader.h"
|
||||
|
||||
static SD_VARLINK_DEFINE_METHOD(
|
||||
Upload,
|
||||
SD_VARLINK_FIELD_COMMENT("Report data as JSON variant. Either this field or reportData (below) have to be specified. This mode is used if signing is not used, and hence a precise binary formatting of the JSON data is not relevant."),
|
||||
SD_VARLINK_DEFINE_INPUT(report, SD_VARLINK_OBJECT, SD_VARLINK_NULLABLE),
|
||||
SD_VARLINK_FIELD_COMMENT("Report data in Base64. Either this field or report (above) have to be specified. This mode is used if signing is enabled, as a precise binary formatting of the JSON data is important to authenticate the signature. This data contains a JSON-SEQ compliant stream of objects, the first being the report, the following ones signature objects."),
|
||||
SD_VARLINK_DEFINE_INPUT(reportData, SD_VARLINK_STRING, SD_VARLINK_NULLABLE));
|
||||
|
||||
SD_VARLINK_DEFINE_INTERFACE(
|
||||
io_systemd_Report_Uploader,
|
||||
"io.systemd.Report.Uploader",
|
||||
SD_VARLINK_INTERFACE_COMMENT("Backend API for uploading reports. This interface shall be implemented by services linked into /run/systemd/report.upload/"),
|
||||
SD_VARLINK_SYMBOL_COMMENT("Upload a report now."),
|
||||
&vl_method_Upload);
|
||||
@@ -0,0 +1,6 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include "sd-varlink-idl.h"
|
||||
|
||||
extern const sd_varlink_interface vl_interface_io_systemd_Report_Uploader;
|
||||
@@ -0,0 +1,26 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "varlink-io.systemd.Report.h"
|
||||
|
||||
static SD_VARLINK_DEFINE_METHOD(
|
||||
Generate,
|
||||
SD_VARLINK_FIELD_COMMENT("Selects which metrics to include in the report, as an array of metric family names or prefixes thereof. If unset or empty all available metrics are included. This matches the [MATCH…] arguments of the systemd-report command line tool."),
|
||||
SD_VARLINK_DEFINE_INPUT(matches, SD_VARLINK_STRING, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
|
||||
SD_VARLINK_FIELD_COMMENT("The generated report as a JSON object. This mode does not sign the report, hence a precise binary formatting of the JSON data is not relevant."),
|
||||
SD_VARLINK_DEFINE_OUTPUT(report, SD_VARLINK_OBJECT, 0));
|
||||
|
||||
static SD_VARLINK_DEFINE_METHOD(
|
||||
GenerateSigned,
|
||||
SD_VARLINK_FIELD_COMMENT("Selects which metrics to include in the report, as an array of metric family names or prefixes thereof. If unset or empty all available metrics are included. This matches the [MATCH…] arguments of the systemd-report command line tool."),
|
||||
SD_VARLINK_DEFINE_INPUT(matches, SD_VARLINK_STRING, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
|
||||
SD_VARLINK_FIELD_COMMENT("The generated, signed report in Base64. A precise binary formatting of the JSON data is important to authenticate the signature. This data contains a JSON-SEQ compliant stream of objects, the first being the report, the following ones signature objects."),
|
||||
SD_VARLINK_DEFINE_OUTPUT(reportData, SD_VARLINK_STRING, 0));
|
||||
|
||||
SD_VARLINK_DEFINE_INTERFACE(
|
||||
io_systemd_Report,
|
||||
"io.systemd.Report",
|
||||
SD_VARLINK_INTERFACE_COMMENT("Frontend API for generating system reports. This interface is implemented by systemd-report, which aggregates the metrics exposed by the io.systemd.Metrics services linked into /run/systemd/report/."),
|
||||
SD_VARLINK_SYMBOL_COMMENT("Generate a report and return it as a JSON object."),
|
||||
&vl_method_Generate,
|
||||
SD_VARLINK_SYMBOL_COMMENT("Generate a signed report and return it Base64 encoded."),
|
||||
&vl_method_GenerateSigned);
|
||||
@@ -0,0 +1,6 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include "sd-varlink-idl.h"
|
||||
|
||||
extern const sd_varlink_interface vl_interface_io_systemd_Report;
|
||||
Reference in New Issue
Block a user