repart: Move verity sig formatting into data partition functions

Refactoring to make implementing rootless repart easier.
This commit is contained in:
Daan De Meyer
2022-10-09 22:30:05 +02:00
parent 2b392d860e
commit 4ecd39c511

View File

@@ -3306,6 +3306,123 @@ static int partition_format_verity_hash(
#endif
}
static int sign_verity_roothash(
const uint8_t *roothash,
size_t roothash_size,
uint8_t **ret_signature,
size_t *ret_signature_size) {
#if HAVE_OPENSSL
_cleanup_(BIO_freep) BIO *rb = NULL;
_cleanup_(PKCS7_freep) PKCS7 *p7 = NULL;
_cleanup_free_ char *hex = NULL;
_cleanup_free_ uint8_t *sig = NULL;
int sigsz;
assert(roothash);
assert(roothash_size > 0);
assert(ret_signature);
assert(ret_signature_size);
hex = hexmem(roothash, roothash_size);
if (!hex)
return log_oom();
rb = BIO_new_mem_buf(hex, -1);
if (!rb)
return log_oom();
p7 = PKCS7_sign(arg_certificate, arg_private_key, NULL, rb, PKCS7_DETACHED|PKCS7_NOATTR|PKCS7_BINARY);
if (!p7)
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to calculate PKCS7 signature: %s",
ERR_error_string(ERR_get_error(), NULL));
sigsz = i2d_PKCS7(p7, &sig);
if (sigsz < 0)
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to convert PKCS7 signature to DER: %s",
ERR_error_string(ERR_get_error(), NULL));
*ret_signature = TAKE_PTR(sig);
*ret_signature_size = sigsz;
return 0;
#else
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "openssl is not supported, cannot setup verity signature: %m");
#endif
}
static int partition_format_verity_sig(Context *context, Partition *p) {
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
_cleanup_free_ uint8_t *sig = NULL;
_cleanup_free_ char *text = NULL;
Partition *hp;
uint8_t fp[X509_FINGERPRINT_SIZE];
size_t sigsz = 0, padsz; /* avoid false maybe-uninitialized warning */
int whole_fd, r;
assert(p->verity == VERITY_SIG);
if (p->dropped)
return 0;
if (PARTITION_EXISTS(p))
return 0;
if (partition_skip(p))
return 0;
assert_se(hp = p->siblings[VERITY_HASH]);
assert(!hp->dropped);
assert(arg_certificate);
assert_se((whole_fd = fdisk_get_devfd(context->fdisk_context)) >= 0);
r = sign_verity_roothash(hp->roothash, hp->roothash_size, &sig, &sigsz);
if (r < 0)
return r;
r = x509_fingerprint(arg_certificate, fp);
if (r < 0)
return log_error_errno(r, "Unable to calculate X509 certificate fingerprint: %m");
r = json_build(&v,
JSON_BUILD_OBJECT(
JSON_BUILD_PAIR("rootHash", JSON_BUILD_HEX(hp->roothash, hp->roothash_size)),
JSON_BUILD_PAIR(
"certificateFingerprint",
JSON_BUILD_HEX(fp, sizeof(fp))
),
JSON_BUILD_PAIR("signature", JSON_BUILD_BASE64(sig, sigsz))
)
);
if (r < 0)
return log_error_errno(r, "Failed to build JSON object: %m");
r = json_variant_format(v, 0, &text);
if (r < 0)
return log_error_errno(r, "Failed to format JSON object: %m");
padsz = round_up_size(strlen(text), 4096);
assert_se(padsz <= p->new_size);
r = strgrowpad0(&text, padsz);
if (r < 0)
return log_error_errno(r, "Failed to pad string to %s", FORMAT_BYTES(padsz));
if (lseek(whole_fd, p->offset, SEEK_SET) == (off_t) -1)
return log_error_errno(errno, "Failed to seek to partition offset: %m");
r = loop_write(whole_fd, text, padsz, /*do_poll=*/ false);
if (r < 0)
return log_error_errno(r, "Failed to write verity signature to partition: %m");
if (fsync(whole_fd) < 0)
return log_error_errno(errno, "Failed to synchronize verity signature JSON: %m");
return 0;
}
static int context_copy_blocks(Context *context) {
int whole_fd = -1, r;
@@ -3372,6 +3489,12 @@ static int context_copy_blocks(Context *context) {
if (r < 0)
return r;
}
if (p->siblings[VERITY_SIG]) {
r = partition_format_verity_sig(context, p->siblings[VERITY_SIG]);
if (r < 0)
return r;
}
}
return 0;
@@ -3737,6 +3860,12 @@ static int context_mkfs(Context *context) {
if (r < 0)
return r;
}
if (p->siblings[VERITY_SIG]) {
r = partition_format_verity_sig(context, p->siblings[VERITY_SIG]);
if (r < 0)
return r;
}
}
return 0;
@@ -3796,130 +3925,6 @@ static int parse_private_key(const char *key, size_t key_size, EVP_PKEY **ret) {
#endif
}
static int sign_verity_roothash(
const uint8_t *roothash,
size_t roothash_size,
uint8_t **ret_signature,
size_t *ret_signature_size) {
#if HAVE_OPENSSL
_cleanup_(BIO_freep) BIO *rb = NULL;
_cleanup_(PKCS7_freep) PKCS7 *p7 = NULL;
_cleanup_free_ char *hex = NULL;
_cleanup_free_ uint8_t *sig = NULL;
int sigsz;
assert(roothash);
assert(roothash_size > 0);
assert(ret_signature);
assert(ret_signature_size);
hex = hexmem(roothash, roothash_size);
if (!hex)
return log_oom();
rb = BIO_new_mem_buf(hex, -1);
if (!rb)
return log_oom();
p7 = PKCS7_sign(arg_certificate, arg_private_key, NULL, rb, PKCS7_DETACHED|PKCS7_NOATTR|PKCS7_BINARY);
if (!p7)
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to calculate PKCS7 signature: %s",
ERR_error_string(ERR_get_error(), NULL));
sigsz = i2d_PKCS7(p7, &sig);
if (sigsz < 0)
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to convert PKCS7 signature to DER: %s",
ERR_error_string(ERR_get_error(), NULL));
*ret_signature = TAKE_PTR(sig);
*ret_signature_size = sigsz;
return 0;
#else
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "openssl is not supported, cannot setup verity signature: %m");
#endif
}
static int context_verity_sig(Context *context) {
int fd = -1, r;
assert(context);
LIST_FOREACH(partitions, p, context->partitions) {
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
_cleanup_free_ uint8_t *sig = NULL;
_cleanup_free_ char *text = NULL;
Partition *hp;
uint8_t fp[X509_FINGERPRINT_SIZE];
size_t sigsz = 0, padsz; /* avoid false maybe-uninitialized warning */
if (p->dropped)
continue;
if (PARTITION_EXISTS(p))
continue;
if (p->verity != VERITY_SIG)
continue;
if (partition_skip(p))
continue;
assert_se(hp = p->siblings[VERITY_HASH]);
assert(!hp->dropped);
assert(arg_certificate);
if (fd < 0)
assert_se((fd = fdisk_get_devfd(context->fdisk_context)) >= 0);
r = sign_verity_roothash(hp->roothash, hp->roothash_size, &sig, &sigsz);
if (r < 0)
return r;
r = x509_fingerprint(arg_certificate, fp);
if (r < 0)
return log_error_errno(r, "Unable to calculate X509 certificate fingerprint: %m");
r = json_build(&v,
JSON_BUILD_OBJECT(
JSON_BUILD_PAIR("rootHash", JSON_BUILD_HEX(hp->roothash, hp->roothash_size)),
JSON_BUILD_PAIR(
"certificateFingerprint",
JSON_BUILD_HEX(fp, sizeof(fp))
),
JSON_BUILD_PAIR("signature", JSON_BUILD_BASE64(sig, sigsz))
)
);
if (r < 0)
return log_error_errno(r, "Failed to build JSON object: %m");
r = json_variant_format(v, 0, &text);
if (r < 0)
return log_error_errno(r, "Failed to format JSON object: %m");
padsz = round_up_size(strlen(text), 4096);
assert_se(padsz <= p->new_size);
r = strgrowpad0(&text, padsz);
if (r < 0)
return log_error_errno(r, "Failed to pad string to %s", FORMAT_BYTES(padsz));
if (lseek(fd, p->offset, SEEK_SET) == (off_t) -1)
return log_error_errno(errno, "Failed to seek to partition offset: %m");
r = loop_write(fd, text, padsz, /*do_poll=*/ false);
if (r < 0)
return log_error_errno(r, "Failed to write verity signature to partition: %m");
if (fsync(fd) < 0)
return log_error_errno(errno, "Failed to synchronize verity signature JSON: %m");
}
return 0;
}
static int partition_acquire_uuid(Context *context, Partition *p, sd_id128_t *ret) {
struct {
sd_id128_t type_uuid;
@@ -4491,10 +4496,6 @@ static int context_write_partition_table(
if (r < 0)
return r;
r = context_verity_sig(context);
if (r < 0)
return r;
r = context_mangle_partitions(context);
if (r < 0)
return r;