mirror of
https://github.com/clearlinux/swupd-client.git
synced 2026-10-03 23:38:25 +00:00
3rd-party: Import certificate from 3rd-party repository on repo add
When trying to add the repository for the first time, download the public certificate published by the 3rd party repository and with a user confirmation, use it to install the 3rd-party os-core. After that the official certificate will be installed for future commands. Signed-off-by: Otavio Pontes <otavio.pontes@intel.com>
This commit is contained in:
@@ -19,9 +19,12 @@
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "3rd_party_repos.h"
|
||||
#include "signature.h"
|
||||
#include "swupd.h"
|
||||
|
||||
#ifdef THIRDPARTY
|
||||
@@ -89,6 +92,138 @@ static int remove_repo(const char *repo_name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool confirm_certificate(const char *cert)
|
||||
{
|
||||
int c;
|
||||
|
||||
info("Importing 3rd-party repository public certificate:\n\n");
|
||||
signature_print_info(cert);
|
||||
|
||||
info("\n");
|
||||
info("Do you want to accept this certificate? (y/N): ");
|
||||
|
||||
c = tolower(getchar());
|
||||
info("\n");
|
||||
|
||||
return c == 'y';
|
||||
}
|
||||
|
||||
static int import_temp_certificate(int version, char *hash)
|
||||
{
|
||||
char *cert_tar, *cert, *url;
|
||||
int ret = 0;
|
||||
|
||||
cert_tar = sys_path_join(globals.state_dir, "temp_cert.tar");
|
||||
cert = sys_path_join(globals.state_dir, hash);
|
||||
|
||||
url = str_or_die("%s/%d/files/%s.tar", globals.content_url, version, hash);
|
||||
|
||||
ret = swupd_curl_get_file(url, cert_tar);
|
||||
if (ret != 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = archives_check_single_file_tarball(cert_tar, hash);
|
||||
if (ret != 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = archives_extract_to(cert_tar, globals.state_dir);
|
||||
if (ret != 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (confirm_certificate(cert)) {
|
||||
signature_deinit();
|
||||
if (!signature_init(cert, NULL)) {
|
||||
signature_deinit();
|
||||
ret = -EPERM;
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
ret = -EACCES;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
unlink(cert_tar);
|
||||
unlink(cert);
|
||||
free(cert);
|
||||
free(cert_tar);
|
||||
free(url);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int import_certificate_from_version(int version)
|
||||
{
|
||||
int ret = 0;
|
||||
char *os_core, *url, *os_core_tar;
|
||||
struct manifest *manifest = NULL;
|
||||
struct list *i;
|
||||
struct file *cert_file = NULL;
|
||||
|
||||
os_core_tar = sys_path_join(globals.state_dir, "temp_manifest.tar");
|
||||
os_core = sys_path_join(globals.state_dir, "Manifest.os-core");
|
||||
url = str_or_die("%s/%d/%s", globals.content_url, version, "Manifest.os-core.tar");
|
||||
|
||||
unlink(os_core_tar);
|
||||
ret = swupd_curl_get_file(url, os_core_tar);
|
||||
if (ret) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = archives_extract_to(os_core_tar, globals.state_dir);
|
||||
if (ret != 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
manifest = manifest_parse("os-core", os_core, false);
|
||||
if (!manifest) {
|
||||
ret = -EPROTO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = manifest->files; i; i = i->next) {
|
||||
struct file *f = i->data;
|
||||
if (strncmp(f->filename, CERT_PATH, sizeof(CERT_PATH)) == 0) {
|
||||
cert_file = f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!cert_file) {
|
||||
ret = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = import_temp_certificate(cert_file->last_change, cert_file->hash);
|
||||
|
||||
out:
|
||||
manifest_free(manifest);
|
||||
unlink(os_core_tar);
|
||||
unlink(os_core);
|
||||
free(os_core);
|
||||
free(os_core_tar);
|
||||
free(url);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int import_third_party_certificate(void)
|
||||
{
|
||||
char *url;
|
||||
int tmp_version;
|
||||
|
||||
url = str_or_die("%s/version/format%s/latest", globals.content_url, globals.format_string);
|
||||
tmp_version = get_int_from_url(url);
|
||||
free(url);
|
||||
|
||||
if (tmp_version <= 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return import_certificate_from_version(tmp_version);
|
||||
}
|
||||
|
||||
enum swupd_code third_party_add_main(int argc, char **argv)
|
||||
{
|
||||
enum swupd_code ret_code = SWUPD_OK;
|
||||
@@ -158,6 +293,23 @@ enum swupd_code third_party_add_main(int argc, char **argv)
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (globals.sigcheck && !globals.user_defined_cert_path) {
|
||||
ret = import_third_party_certificate();
|
||||
if (ret < 0) {
|
||||
if (ret == -ENOENT) {
|
||||
error("Public certificate not found on 3rd-party repository\n");
|
||||
info("To ignore certificate check use --nosigcheck\n");
|
||||
} else if (ret != -EACCES) {
|
||||
error("Impossible to import 3rd party repository certificate\n");
|
||||
info("To ignore certificate check use --nosigcheck\n");
|
||||
}
|
||||
revert = true;
|
||||
|
||||
ret_code = SWUPD_BAD_CERT;
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
|
||||
/* get repo's latest version */
|
||||
repo_version = get_latest_version(repo->url);
|
||||
if (repo_version < 0) {
|
||||
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
#!/usr/bin/env bats
|
||||
|
||||
# Author: Otavio Pontes
|
||||
# Email: otavio.pontes@intel.com
|
||||
|
||||
load "../testlib"
|
||||
|
||||
export repo1
|
||||
export repo2
|
||||
|
||||
global_setup() {
|
||||
# Skip this test for local development because we write the certificate on /
|
||||
# This is necessary because the default certificate location is hardcoded on build time and we
|
||||
# need to run swupd without -C parameter to test this feature.
|
||||
if [ -z "${RUNNING_IN_CI}" ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
if [ ! -f /usr/share/clear/update-ca/Swupd_Root.pem ]; then
|
||||
sudo mkdir -p /usr/share/clear/update-ca
|
||||
sudo cp "$TEST_ROOT_DIR"/Swupd_Root.pem /usr/share/clear/update-ca
|
||||
export CERT_WAS_INSTALLED=1
|
||||
fi
|
||||
}
|
||||
|
||||
global_teardown() {
|
||||
|
||||
if [ -z "${RUNNING_IN_CI}" ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
if [ ! -z "${CERT_WAS_INSTALLED}" ]; then
|
||||
sudo rm usr/share/clear/update-ca/Swupd_Root.pem
|
||||
fi
|
||||
}
|
||||
|
||||
test_setup() {
|
||||
|
||||
create_test_environment "$TEST_NAME"
|
||||
create_third_party_repo "$TEST_NAME" 10 staging test-repo1
|
||||
repo1="$TPWEBDIR"
|
||||
create_third_party_repo "$TEST_NAME" 10 staging test-repo2
|
||||
repo2="$TPWEBDIR"
|
||||
}
|
||||
|
||||
@test "TPR066: Add a single repo importing the certificate" {
|
||||
|
||||
run sudo sh -c "echo 'y' | $SWUPD 3rd-party add test-repo1 file://$repo1 $SWUPD_OPTS_NO_CERT"
|
||||
assert_status_is "$SWUPD_OK"
|
||||
expected_output=$(cat <<-EOM
|
||||
Adding 3rd-party repository test-repo1...
|
||||
Importing 3rd-party repository public certificate:
|
||||
Issuer: /C=US/ST=Oregon/L=Portland/O=Company Name/OU=Org/CN=localhost
|
||||
Subject: /C=US/ST=Oregon/L=Portland/O=Company Name/OU=Org/CN=localhost
|
||||
.*
|
||||
Installing the required bundle 'os-core' from the repository...
|
||||
Note that all bundles added from a 3rd-party repository are forced to run with the --no-scripts flag for security reasons
|
||||
Loading required manifests...
|
||||
Downloading packs for:
|
||||
- os-core
|
||||
Finishing packs extraction...
|
||||
Validate downloaded files
|
||||
No extra files need to be downloaded
|
||||
Installing files...
|
||||
Warning: post-update helper scripts skipped due to --no-scripts argument
|
||||
Successfully installed 1 bundle
|
||||
Repository added successfully
|
||||
EOM
|
||||
)
|
||||
assert_regex_is_output "$expected_output"
|
||||
|
||||
run sudo sh -c "cat $STATEDIR/3rd-party/repo.ini"
|
||||
expected_output=$(cat <<-EOM
|
||||
[test-repo1]
|
||||
url=file://$repo1
|
||||
EOM
|
||||
)
|
||||
assert_is_output "$expected_output"
|
||||
|
||||
# make sure the os-core bundle of the repo is installed in the appropriate place
|
||||
assert_file_exists "$TARGETDIR"/"$THIRD_PARTY_BUNDLES_DIR"/test-repo1/usr/share/clear/bundles/os-core
|
||||
assert_file_exists "$TARGETDIR"/"$THIRD_PARTY_BUNDLES_DIR"/test-repo1/usr/lib/os-release
|
||||
|
||||
}
|
||||
|
||||
@test "TPR067: Reject a certificate when adding a repository" {
|
||||
|
||||
run sudo sh -c "echo 'n' | $SWUPD 3rd-party add test-repo1 file://$repo1 $SWUPD_OPTS_NO_CERT"
|
||||
assert_status_is "$SWUPD_BAD_CERT"
|
||||
expected_output=$(cat <<-EOM
|
||||
Adding 3rd-party repository test-repo1...
|
||||
Importing 3rd-party repository public certificate:
|
||||
Issuer: /C=US/ST=Oregon/L=Portland/O=Company Name/OU=Org/CN=localhost
|
||||
Subject: /C=US/ST=Oregon/L=Portland/O=Company Name/OU=Org/CN=localhost
|
||||
.*
|
||||
Failed to add repository
|
||||
EOM
|
||||
)
|
||||
assert_regex_is_output "$expected_output"
|
||||
}
|
||||
Reference in New Issue
Block a user