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:
Tudor Marcu
2017-01-25 15:00:24 -08:00
committed by tmarcu
parent cd110a1875
commit 428d09d003
10 changed files with 79 additions and 15 deletions
+1
View File
@@ -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
View File
@@ -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;
+6 -1
View File
@@ -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
View File
@@ -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");
+1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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");