mirror of
https://github.com/clearlinux/swupd-client.git
synced 2026-10-03 15:29:29 +00:00
Move signature verification to mandatory
This sets swupd signature verification to mandatory, failing and exiting for any verify error, though --nosigcheck enables user to bypass all signature-based security checks. The signed MoM serves as the top level chain of trust, and it is used to extend content trust down to the individual file level. When the signature of the top-level MoM is invalid or cannot be verified for any reason, we warn and abort the operation. Passing --nosigcheck will allow this to proceed, explicitly accepting the unverifiable MoM and outputting a log entry to the Journal. This is not recommended and unsupported by upstream once the chain of security is broken, because it may imply update content was or may be installed that was not generated by the official upstream. Signed-off-by: Brad T. Peters <brad.t.peters@intel.com> Signed-off-by: Tudor Marcu <tudor.marcu@intel.com>
This commit is contained in:
@@ -65,6 +65,7 @@ struct version_container {
|
||||
struct header;
|
||||
|
||||
extern bool force;
|
||||
extern bool sigcheck;
|
||||
extern int verbose;
|
||||
extern int update_count;
|
||||
extern int update_skip;
|
||||
|
||||
+6
-1
@@ -41,6 +41,7 @@ static void print_help(const char *name)
|
||||
printf(" -P, --port=[port #] Port number to connect to at the url for version string and content file downloads\n");
|
||||
printf(" -F, --format=[staging,1,2,etc.] the format suffix for version file downloads\n");
|
||||
printf(" -x, --force Attempt to proceed even if non-critical errors found\n");
|
||||
printf(" -n, --nosigcheck Do not attempt to enforce certificate or signature checking\n");
|
||||
printf(" -p, --path=[PATH...] Use [PATH...] as the path to verify (eg: a chroot or btrfs subvol\n");
|
||||
printf(" -S, --statedir Specify alternate swupd state directory\n");
|
||||
printf("\n");
|
||||
@@ -53,6 +54,7 @@ static const struct option prog_opts[] = {
|
||||
{ "port", required_argument, 0, 'P' },
|
||||
{ "format", required_argument, 0, 'F' },
|
||||
{ "force", no_argument, 0, 'x' },
|
||||
{ "nosigcheck", no_argument, 0, 'n' },
|
||||
{ "path", required_argument, 0, 'p' },
|
||||
{ "statedir", required_argument, 0, 'S' },
|
||||
{ 0, 0, 0, 0 }
|
||||
@@ -62,7 +64,7 @@ static bool parse_options(int argc, char **argv)
|
||||
{
|
||||
int opt;
|
||||
|
||||
while ((opt = getopt_long(argc, argv, "hxu:v:P:F:p:S:", prog_opts, NULL)) != -1) {
|
||||
while ((opt = getopt_long(argc, argv, "hxnu:v:P:F:p:S:", prog_opts, NULL)) != -1) {
|
||||
switch (opt) {
|
||||
case '?':
|
||||
case 'h':
|
||||
@@ -111,6 +113,9 @@ static bool parse_options(int argc, char **argv)
|
||||
case 'x':
|
||||
force = true;
|
||||
break;
|
||||
case 'n':
|
||||
sigcheck = false;
|
||||
break;
|
||||
default:
|
||||
printf("error: unrecognized option\n\n");
|
||||
goto err;
|
||||
|
||||
@@ -52,6 +52,7 @@ static void print_help(const char *name)
|
||||
printf(" -F, --format=[staging,1,2,etc.] the format suffix for version file downloads\n");
|
||||
printf(" -l, --list List all available bundles for the current version of Clear Linux\n");
|
||||
printf(" -x, --force Attempt to proceed even if non-critical errors found\n");
|
||||
printf(" -n, --nosigcheck Do not attempt to enforce certificate or signature checking\n");
|
||||
printf(" -S, --statedir Specify alternate swupd state directory\n");
|
||||
printf(" -C, --certpath Specify alternate path to swupd certificates\n");
|
||||
printf("\n");
|
||||
@@ -67,6 +68,7 @@ static const struct option prog_opts[] = {
|
||||
{ "path", required_argument, 0, 'p' },
|
||||
{ "format", required_argument, 0, 'F' },
|
||||
{ "force", no_argument, 0, 'x' },
|
||||
{ "nosigcheck", no_argument, 0, 'n' },
|
||||
{ "statedir", required_argument, 0, 'S' },
|
||||
{ "certpath", required_argument, 0, 'C' },
|
||||
{ 0, 0, 0, 0 }
|
||||
@@ -76,7 +78,7 @@ static bool parse_options(int argc, char **argv)
|
||||
{
|
||||
int opt;
|
||||
|
||||
while ((opt = getopt_long(argc, argv, "hxu:c:v:P:p:F:lS:C:", prog_opts, NULL)) != -1) {
|
||||
while ((opt = getopt_long(argc, argv, "hxnu:c:v:P:p:F:lS:C:", prog_opts, NULL)) != -1) {
|
||||
switch (opt) {
|
||||
case '?':
|
||||
case 'h':
|
||||
@@ -134,6 +136,9 @@ static bool parse_options(int argc, char **argv)
|
||||
case 'x':
|
||||
force = true;
|
||||
break;
|
||||
case 'n':
|
||||
sigcheck = false;
|
||||
break;
|
||||
case 'C':
|
||||
if (!optarg) {
|
||||
printf("Invalid --certpath argument\n\n");
|
||||
|
||||
+6
-1
@@ -51,6 +51,7 @@ static void print_help(const char *name)
|
||||
printf(" -P, --port=[port #] Port number to connect to at the url for version string and content file downloads\n");
|
||||
printf(" -F, --format=[staging,1,2,etc.] the format suffix for version file downloads\n");
|
||||
printf(" -x, --force Attempt to proceed even if non-critical errors found\n");
|
||||
printf(" -n, --nosigcheck Do not attempt to enforce certificate or signature checks\n");
|
||||
printf(" -S, --statedir Specify alternate swupd state directory\n");
|
||||
printf(" -C, --certpath Specify alternate path to swupd certificates\n");
|
||||
printf("\n");
|
||||
@@ -65,6 +66,7 @@ static const struct option prog_opts[] = {
|
||||
{ "port", required_argument, 0, 'P' },
|
||||
{ "format", required_argument, 0, 'F' },
|
||||
{ "force", no_argument, 0, 'x' },
|
||||
{ "nosigcheck", no_argument, 0, 'n' },
|
||||
{ "statedir", required_argument, 0, 'S' },
|
||||
{ "certpath", required_argument, 0, 'C' },
|
||||
{ 0, 0, 0, 0 }
|
||||
@@ -74,7 +76,7 @@ static bool parse_options(int argc, char **argv)
|
||||
{
|
||||
int opt;
|
||||
|
||||
while ((opt = getopt_long(argc, argv, "hxp:u:c:v:P:F:S:C:", prog_opts, NULL)) != -1) {
|
||||
while ((opt = getopt_long(argc, argv, "hxnp:u:c:v:P:F:S:C:", prog_opts, NULL)) != -1) {
|
||||
switch (opt) {
|
||||
case '?':
|
||||
case 'h':
|
||||
@@ -129,6 +131,9 @@ static bool parse_options(int argc, char **argv)
|
||||
case 'x':
|
||||
force = true;
|
||||
break;
|
||||
case 'n':
|
||||
sigcheck = false;
|
||||
break;
|
||||
case 'C':
|
||||
if (!optarg) {
|
||||
printf("Invalid --certpath argument\n\n");
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include "swupd.h"
|
||||
|
||||
bool force = false;
|
||||
bool sigcheck = true;
|
||||
bool verify_esp_only;
|
||||
bool verify_bundles_only = false;
|
||||
int update_count = 0;
|
||||
|
||||
+2
-1
@@ -614,7 +614,8 @@ int swupd_init(int *lock_fd)
|
||||
goto out_close_lock;
|
||||
}
|
||||
|
||||
if (!initialize_signature()) {
|
||||
/* If --nosigcheck, we do not attempt any signature checking */
|
||||
if (sigcheck && !initialize_signature()) {
|
||||
ret = ESIGNATURE;
|
||||
terminate_signature();
|
||||
goto out_close_lock;
|
||||
|
||||
+6
-1
@@ -46,6 +46,7 @@ static const struct option prog_opts[] = {
|
||||
{ "format", required_argument, 0, 'F' },
|
||||
{ "path", required_argument, 0, 'p' },
|
||||
{ "force", no_argument, 0, 'x' },
|
||||
{ "nosigcheck", no_argument, 0, 'n' },
|
||||
{ "statedir", required_argument, 0, 'S' },
|
||||
{ "certpath", required_argument, 0, 'C' },
|
||||
{ 0, 0, 0, 0 }
|
||||
@@ -70,6 +71,7 @@ static void print_help(const char *name)
|
||||
printf(" -F, --format=[staging,1,2,etc.] the format suffix for version file downloads\n");
|
||||
printf(" -p, --path=[PATH...] Use [PATH...] as the path to verify (eg: a chroot or btrfs subvol\n");
|
||||
printf(" -x, --force Attempt to proceed even if non-critical errors found\n");
|
||||
printf(" -n, --nosigcheck Do not attempt to enforce certificate or signature checking\n");
|
||||
printf(" -S, --statedir Specify alternate swupd state directory\n");
|
||||
printf(" -C, --certpath Specify alternate path to swupd certificates\n");
|
||||
printf("\n");
|
||||
@@ -79,7 +81,7 @@ static bool parse_options(int argc, char **argv)
|
||||
{
|
||||
int opt;
|
||||
|
||||
while ((opt = getopt_long(argc, argv, "hxdu:P:c:v:sF:p:S:C:", prog_opts, NULL)) != -1) {
|
||||
while ((opt = getopt_long(argc, argv, "hxndu:P:c:v:sF:p:S:C:", prog_opts, NULL)) != -1) {
|
||||
switch (opt) {
|
||||
case '?':
|
||||
case 'h':
|
||||
@@ -140,6 +142,9 @@ static bool parse_options(int argc, char **argv)
|
||||
case 'x':
|
||||
force = true;
|
||||
break;
|
||||
case 'n':
|
||||
sigcheck = false;
|
||||
break;
|
||||
case 'C':
|
||||
if (!optarg) {
|
||||
printf("Invalid --certpath argument\n\n");
|
||||
|
||||
+14
-1
@@ -584,6 +584,7 @@ struct manifest *load_mom(int version)
|
||||
int ret = 0;
|
||||
char *filename;
|
||||
char *url;
|
||||
char *log_cmd = NULL;
|
||||
|
||||
ret = retrieve_manifests(version, version, "MoM", NULL);
|
||||
if (ret != 0) {
|
||||
@@ -594,7 +595,19 @@ struct manifest *load_mom(int version)
|
||||
string_or_die(&filename, "%s/%i/Manifest.MoM", state_dir, version);
|
||||
string_or_die(&url, "%s/%i/Manifest.MoM", content_url, version);
|
||||
if (!download_and_verify_signature(url, filename)) {
|
||||
printf("WARNING!!! FAILED TO VERIFY SIGNATURE OF Manifest.MoM\n");
|
||||
if (sigcheck) {
|
||||
printf("WARNING!!! FAILED TO VERIFY SIGNATURE OF Manifest.MoM\n");
|
||||
free(filename);
|
||||
free(url);
|
||||
return NULL;
|
||||
} else {
|
||||
printf("FAILED TO VERIFY SIGNATURE OF Manifest.MoM. Operation proceeding due to\n"
|
||||
" --nosigcheck, but system security may be compromised\n");
|
||||
string_or_die(&log_cmd, "echo \"swupd security notice:"
|
||||
" --nosigcheck used to bypass MoM signature verification failure\" | systemd-cat --priority=\"err\" --identifier=\"swupd\"");
|
||||
(void)system(log_cmd);
|
||||
free(log_cmd);
|
||||
}
|
||||
}
|
||||
free(filename);
|
||||
free(url);
|
||||
|
||||
+31
-8
@@ -29,6 +29,7 @@
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <openssl/bio.h>
|
||||
@@ -44,7 +45,7 @@
|
||||
|
||||
static char *CERTNAME;
|
||||
|
||||
static bool validate_certificate(void);
|
||||
static int validate_certificate(void);
|
||||
static int verify_callback(int, X509_STORE_CTX *);
|
||||
static bool get_pubkey();
|
||||
|
||||
@@ -64,6 +65,11 @@ static char *crl = NULL;
|
||||
* returns: true if can initialize and validate certificates, otherwise false */
|
||||
bool initialize_signature(void)
|
||||
{
|
||||
int ret = -1;
|
||||
time_t mod_sec = 0;
|
||||
struct tm *alttime;
|
||||
struct stat statt;
|
||||
|
||||
string_or_die(&CERTNAME, "%s/%s", cert_path, SWUPDCERT);
|
||||
|
||||
ERR_load_crypto_strings();
|
||||
@@ -73,7 +79,20 @@ bool initialize_signature(void)
|
||||
if (!get_pubkey()) {
|
||||
goto fail;
|
||||
}
|
||||
if (!validate_certificate()) {
|
||||
|
||||
ret = validate_certificate();
|
||||
if (ret) {
|
||||
printf("Failed to verify certificate: %s\n", X509_verify_cert_error_string(ret));
|
||||
if (ret == X509_V_ERR_CERT_NOT_YET_VALID) {
|
||||
/* If we can retrieve an approx. good system time, report out to user */
|
||||
if (stat("/usr/lib/os-release", &statt) != -1) {
|
||||
mod_sec = statt.st_mtim.tv_sec;
|
||||
char timebuf[30];
|
||||
alttime = localtime(&mod_sec);
|
||||
strftime(timebuf, sizeof(timebuf), "%F", alttime);
|
||||
printf("System clock should be at least %s\n", timebuf);
|
||||
}
|
||||
}
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@@ -282,8 +301,8 @@ error:
|
||||
* keys have not been compromised or the CRL has not been generated by the
|
||||
* Certificate Authority (CA)
|
||||
*
|
||||
* returns: true if certificate is valid, false otherwise */
|
||||
static bool validate_certificate(void)
|
||||
* returns: 0 if certificate is valid, X509 store error code otherwise */
|
||||
static int validate_certificate(void)
|
||||
{
|
||||
X509_LOOKUP *lookup = NULL;
|
||||
X509_STORE_CTX *verify_ctx = NULL;
|
||||
@@ -353,7 +372,7 @@ static bool validate_certificate(void)
|
||||
X509_STORE_CTX_free(verify_ctx);
|
||||
|
||||
/* Certificate verified correctly */
|
||||
return true;
|
||||
return 0;
|
||||
|
||||
error:
|
||||
ERR_print_errors_fp(stderr);
|
||||
@@ -362,14 +381,14 @@ error:
|
||||
X509_STORE_CTX_free(verify_ctx);
|
||||
}
|
||||
|
||||
return false;
|
||||
return verify_ctx->error;
|
||||
}
|
||||
|
||||
int verify_callback(int ok, X509_STORE_CTX *stor)
|
||||
{
|
||||
if (!ok) {
|
||||
fprintf(stderr, "Certificate verification error: %s\n",
|
||||
X509_verify_cert_error_string(stor->error));
|
||||
printf("Certificate verification error: %s\n",
|
||||
X509_verify_cert_error_string(stor->error));
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
@@ -387,6 +406,10 @@ bool download_and_verify_signature(const char *data_url, const char *data_filena
|
||||
int ret;
|
||||
bool result;
|
||||
|
||||
if (!sigcheck) {
|
||||
return false;
|
||||
}
|
||||
|
||||
string_or_die(&sig_url, "%s.sig", data_url);
|
||||
|
||||
string_or_die(&sig_filename, "%s.sig", data_filename);
|
||||
|
||||
+6
-1
@@ -67,6 +67,7 @@ static const struct option prog_opts[] = {
|
||||
{ "format", required_argument, 0, 'F' },
|
||||
{ "quick", no_argument, 0, 'q' },
|
||||
{ "force", no_argument, 0, 'x' },
|
||||
{ "nosigcheck", no_argument, 0, 'n' },
|
||||
{ "statedir", required_argument, 0, 'S' },
|
||||
{ "certpath", required_argument, 0, 'C' },
|
||||
{ 0, 0, 0, 0 }
|
||||
@@ -90,6 +91,7 @@ static void print_help(const char *name)
|
||||
printf(" -F, --format=[staging,1,2,etc.] the format suffix for version file downloads\n");
|
||||
printf(" -q, --quick Don't compare hashes, only fix missing files\n");
|
||||
printf(" -x, --force Attempt to proceed even if non-critical errors found\n");
|
||||
printf(" -n, --nosigcheck Do not attempt to enforce certificate or signature checking\n");
|
||||
printf(" -S, --statedir Specify alternate swupd state directory\n");
|
||||
printf(" -C, --certpath Specify alternate path to swupd certificates\n");
|
||||
printf("\n");
|
||||
@@ -99,7 +101,7 @@ static bool parse_options(int argc, char **argv)
|
||||
{
|
||||
int opt;
|
||||
|
||||
while ((opt = getopt_long(argc, argv, "hxm:p:u:P:c:v:fiF:qS:C:", prog_opts, NULL)) != -1) {
|
||||
while ((opt = getopt_long(argc, argv, "hxnm:p:u:P:c:v:fiF:qS:C:", prog_opts, NULL)) != -1) {
|
||||
switch (opt) {
|
||||
case '?':
|
||||
case 'h':
|
||||
@@ -172,6 +174,9 @@ static bool parse_options(int argc, char **argv)
|
||||
case 'x':
|
||||
force = true;
|
||||
break;
|
||||
case 'n':
|
||||
sigcheck = false;
|
||||
break;
|
||||
case 'C':
|
||||
if (!optarg) {
|
||||
printf("Invalid --certpath argument\n\n");
|
||||
|
||||
Reference in New Issue
Block a user