summaryrefslogtreecommitdiff
path: root/futility
diff options
context:
space:
mode:
authorRandall Spangler <rspangler@chromium.org>2016-06-23 13:45:59 -0700
committerchrome-bot <chrome-bot@chromium.org>2016-09-02 01:28:37 -0700
commitf7559e4b4652134b1e15de3ce31ee50a3de00f69 (patch)
tree63c14345dbe8323ad25a428c936a1c51f6ae7fcc /futility
parentdf2bd9b1e74687dfc82a7bacc0b9a3c6162c0504 (diff)
downloadvboot-f7559e4b4652134b1e15de3ce31ee50a3de00f69.tar.gz
futility: Use vboot 2.0 APIs for public keys
This replaces calls to the old vboot 1 APIs with their vboot 2.0 equivalents. BUG=chromium:611535 BRANCH=none TEST=make runtests Change-Id: Ieb1a127577c6428c47ac088c3aaa0d0dad6275a8 Signed-off-by: Randall Spangler <rspangler@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/356541 Reviewed-by: Daisuke Nojiri <dnojiri@chromium.org>
Diffstat (limited to 'futility')
-rw-r--r--futility/cmd_create.c12
-rw-r--r--futility/cmd_sign.c38
-rw-r--r--futility/cmd_vbutil_firmware.c11
-rw-r--r--futility/cmd_vbutil_kernel.c4
-rw-r--r--futility/cmd_vbutil_key.c42
-rw-r--r--futility/cmd_vbutil_keyblock.c12
-rw-r--r--futility/file_type_bios.c13
-rw-r--r--futility/futility_options.h4
-rw-r--r--futility/vb1_helper.c55
-rw-r--r--futility/vb1_helper.h2
10 files changed, 98 insertions, 95 deletions
diff --git a/futility/cmd_create.c b/futility/cmd_create.c
index 748ce2f7..c8219511 100644
--- a/futility/cmd_create.c
+++ b/futility/cmd_create.c
@@ -15,6 +15,7 @@
#include "2rsa.h"
#include "2sha.h"
#include "util_misc.h"
+#include "vb2_common.h"
#include "vb21_common.h"
#include "host_key.h"
@@ -81,7 +82,7 @@ static void print_help(int argc, char *argv[])
static int vb1_make_keypair()
{
struct vb2_private_key *privkey = NULL;
- VbPublicKey *pubkey = 0;
+ struct vb2_packed_key *pubkey = NULL;
struct rsa_st *rsa_key = NULL;
uint8_t *keyb_data = 0;
uint32_t keyb_size;
@@ -136,14 +137,14 @@ static int vb1_make_keypair()
goto done;
}
- pubkey = PublicKeyAlloc(keyb_size, vb1_algorithm, opt_version);
+ pubkey = vb2_alloc_packed_key(keyb_size, vb1_algorithm, opt_version);
if (!pubkey)
goto done;
- memcpy(GetPublicKeyData(pubkey), keyb_data, keyb_size);
+ memcpy((uint8_t *)vb2_packed_key_data(pubkey), keyb_data, keyb_size);
/* Write it out */
strcpy(outext, ".vbpubk");
- if (0 != PublicKeyWrite(outfile, pubkey)) {
+ if (VB2_SUCCESS != vb2_write_packed_key(outfile, pubkey)) {
fprintf(stderr, "unable to write public key\n");
goto done;
}
@@ -214,7 +215,8 @@ static int vb2_make_keypair()
privkey->sig_alg = sig_alg;
privkey->hash_alg = opt_hash_alg;
if (opt_desc && vb2_private_key_set_desc(privkey, opt_desc)) {
- fprintf(stderr, "Unable to set the private key description\n");
+ fprintf(stderr,
+ "Unable to set the private key description\n");
goto done;
}
}
diff --git a/futility/cmd_sign.c b/futility/cmd_sign.c
index 3ff6ddac..0792081e 100644
--- a/futility/cmd_sign.c
+++ b/futility/cmd_sign.c
@@ -78,22 +78,22 @@ int ft_sign_pubkey(const char *name, uint8_t *buf, uint32_t len, void *data)
sign_option.flags,
sign_option.pem_external);
} else {
- sign_option.signprivate2 = vb2_read_private_key_pem(
+ sign_option.signprivate = vb2_read_private_key_pem(
sign_option.pem_signpriv,
sign_option.pem_algo);
- if (!sign_option.signprivate2) {
+ if (!sign_option.signprivate) {
fprintf(stderr,
"Unable to read PEM signing key: %s\n",
strerror(errno));
return 1;
}
block = vb2_create_keyblock(data_key,
- sign_option.signprivate2,
+ sign_option.signprivate,
sign_option.flags);
}
} else {
/* Not PEM. Should already have a signing key. */
- block = vb2_create_keyblock(data_key, sign_option.signprivate2,
+ block = vb2_create_keyblock(data_key, sign_option.signprivate,
sign_option.flags);
}
@@ -130,7 +130,7 @@ int ft_sign_raw_kernel(const char *name, uint8_t *buf, uint32_t len,
sign_option.version,
sign_option.kloadaddr,
sign_option.keyblock,
- sign_option.signprivate2,
+ sign_option.signprivate,
sign_option.flags, &vblock_size);
if (!vblock_data) {
fprintf(stderr, "Unable to sign kernel blob\n");
@@ -217,7 +217,7 @@ int ft_sign_kern_preamble(const char *name, uint8_t *buf, uint32_t len,
sign_option.version,
sign_option.kloadaddr,
keyblock,
- sign_option.signprivate2,
+ sign_option.signprivate,
sign_option.flags,
&vblock_size);
if (!vblock_data) {
@@ -255,7 +255,7 @@ int ft_sign_raw_firmware(const char *name, uint8_t *buf, uint32_t len,
struct vb2_fw_preamble *preamble;
int rv;
- body_sig = vb2_calculate_signature(buf, len, sign_option.signprivate2);
+ body_sig = vb2_calculate_signature(buf, len, sign_option.signprivate);
if (!body_sig) {
fprintf(stderr, "Error calculating body signature\n");
return 1;
@@ -265,7 +265,7 @@ int ft_sign_raw_firmware(const char *name, uint8_t *buf, uint32_t len,
sign_option.version,
(struct vb2_packed_key *)sign_option.kernel_subkey,
body_sig,
- sign_option.signprivate2,
+ sign_option.signprivate,
sign_option.flags);
if (!preamble) {
fprintf(stderr, "Error creating firmware preamble.\n");
@@ -654,8 +654,8 @@ static int do_sign(int argc, char *argv[])
&longindex)) != -1) {
switch (i) {
case 's':
- sign_option.signprivate2 = vb2_read_private_key(optarg);
- if (!sign_option.signprivate2) {
+ sign_option.signprivate = vb2_read_private_key(optarg);
+ if (!sign_option.signprivate) {
fprintf(stderr, "Error reading %s\n", optarg);
errorcnt++;
}
@@ -668,7 +668,7 @@ static int do_sign(int argc, char *argv[])
}
break;
case 'k':
- sign_option.kernel_subkey = PublicKeyRead(optarg);
+ sign_option.kernel_subkey = vb2_read_packed_key(optarg);
if (!sign_option.kernel_subkey) {
fprintf(stderr, "Error reading %s\n", optarg);
errorcnt++;
@@ -908,13 +908,13 @@ static int do_sign(int argc, char *argv[])
switch (sign_option.type) {
case FILE_TYPE_PUBKEY:
sign_option.create_new_outfile = 1;
- if (sign_option.signprivate2 && sign_option.pem_signpriv) {
+ if (sign_option.signprivate && sign_option.pem_signpriv) {
fprintf(stderr,
"Only one of --signprivate and --pem_signpriv"
" can be specified\n");
errorcnt++;
}
- if ((sign_option.signprivate2 &&
+ if ((sign_option.signprivate &&
sign_option.pem_algo_specified) ||
(sign_option.pem_signpriv &&
!sign_option.pem_algo_specified)) {
@@ -932,18 +932,18 @@ static int do_sign(int argc, char *argv[])
break;
case FILE_TYPE_BIOS_IMAGE:
case FILE_TYPE_OLD_BIOS_IMAGE:
- errorcnt += no_opt_if(!sign_option.signprivate2, "signprivate");
+ errorcnt += no_opt_if(!sign_option.signprivate, "signprivate");
errorcnt += no_opt_if(!sign_option.keyblock, "keyblock");
errorcnt += no_opt_if(!sign_option.kernel_subkey, "kernelkey");
break;
case FILE_TYPE_KERN_PREAMBLE:
- errorcnt += no_opt_if(!sign_option.signprivate2, "signprivate");
+ errorcnt += no_opt_if(!sign_option.signprivate, "signprivate");
if (sign_option.vblockonly || sign_option.inout_file_count > 1)
sign_option.create_new_outfile = 1;
break;
case FILE_TYPE_RAW_FIRMWARE:
sign_option.create_new_outfile = 1;
- errorcnt += no_opt_if(!sign_option.signprivate2, "signprivate");
+ errorcnt += no_opt_if(!sign_option.signprivate, "signprivate");
errorcnt += no_opt_if(!sign_option.keyblock, "keyblock");
errorcnt += no_opt_if(!sign_option.kernel_subkey, "kernelkey");
errorcnt += no_opt_if(!sign_option.version_specified,
@@ -951,7 +951,7 @@ static int do_sign(int argc, char *argv[])
break;
case FILE_TYPE_RAW_KERNEL:
sign_option.create_new_outfile = 1;
- errorcnt += no_opt_if(!sign_option.signprivate2, "signprivate");
+ errorcnt += no_opt_if(!sign_option.signprivate, "signprivate");
errorcnt += no_opt_if(!sign_option.keyblock, "keyblock");
errorcnt += no_opt_if(!sign_option.version_specified,
"version");
@@ -1044,8 +1044,8 @@ done:
strerror(errno));
}
- if (sign_option.signprivate2)
- free(sign_option.signprivate2);
+ if (sign_option.signprivate)
+ free(sign_option.signprivate);
if (sign_option.keyblock)
free(sign_option.keyblock);
if (sign_option.kernel_subkey)
diff --git a/futility/cmd_vbutil_firmware.c b/futility/cmd_vbutil_firmware.c
index 4f44426b..950690a0 100644
--- a/futility/cmd_vbutil_firmware.c
+++ b/futility/cmd_vbutil_firmware.c
@@ -285,12 +285,11 @@ static int do_verify(const char *infile, const char *signpubkey,
return 1;
}
- if (kernelkey_file) {
- if (0 != PublicKeyWrite(kernelkey_file,
- (struct VbPublicKey *)kernel_subkey)) {
- VbExError("Unable to write kernel subkey\n");
- return 1;
- }
+ if (kernelkey_file &&
+ VB2_SUCCESS != vb2_write_packed_key(kernelkey_file,
+ kernel_subkey)) {
+ VbExError("Unable to write kernel subkey\n");
+ return 1;
}
return 0;
diff --git a/futility/cmd_vbutil_kernel.c b/futility/cmd_vbutil_kernel.c
index 274ea75f..cc6b83c0 100644
--- a/futility/cmd_vbutil_kernel.c
+++ b/futility/cmd_vbutil_kernel.c
@@ -240,7 +240,7 @@ static int do_vbutil_kernel(int argc, char *argv[])
struct vb2_keyblock *keyblock = NULL;
struct vb2_keyblock *t_keyblock = NULL;
struct vb2_private_key *signpriv_key = NULL;
- VbPublicKey *signpub_key = NULL;
+ struct vb2_packed_key *signpub_key = NULL;
uint8_t *kpart_data = NULL;
uint64_t kpart_size = 0;
uint8_t *vmlinuz_buf = NULL;
@@ -547,7 +547,7 @@ static int do_vbutil_kernel(int argc, char *argv[])
/* Optional */
if (signpubkey_file) {
- signpub_key = PublicKeyRead(signpubkey_file);
+ signpub_key = vb2_read_packed_key(signpubkey_file);
if (!signpub_key)
Fatal("Error reading public key.\n");
}
diff --git a/futility/cmd_vbutil_key.c b/futility/cmd_vbutil_key.c
index 7f61e0a5..58f724c7 100644
--- a/futility/cmd_vbutil_key.c
+++ b/futility/cmd_vbutil_key.c
@@ -76,16 +76,15 @@ static void print_help(int argc, char *argv[])
static int do_pack(const char *infile, const char *outfile, uint32_t algorithm,
uint32_t version)
{
- VbPublicKey *pubkey;
-
if (!infile || !outfile) {
fprintf(stderr, "vbutil_key: Must specify --in and --out\n");
return 1;
}
- pubkey = PublicKeyReadKeyb(infile, algorithm, version);
+ struct vb2_packed_key *pubkey =
+ vb2_read_packed_keyb(infile, algorithm, version);
if (pubkey) {
- if (0 != PublicKeyWrite(outfile, pubkey)) {
+ if (0 != vb2_write_packed_key(outfile, pubkey)) {
fprintf(stderr, "vbutil_key: Error writing key.\n");
return 1;
}
@@ -111,28 +110,26 @@ static int do_pack(const char *infile, const char *outfile, uint32_t algorithm,
/* Unpack a .vbpubk or .vbprivk */
static int do_unpack(const char *infile, const char *outfile)
{
- VbPublicKey *pubkey;
+ struct vb2_packed_key *pubkey;
if (!infile) {
fprintf(stderr, "Need file to unpack\n");
return 1;
}
- pubkey = PublicKeyRead(infile);
+ pubkey = vb2_read_packed_key(infile);
if (pubkey) {
printf("Public Key file: %s\n", infile);
- printf("Algorithm: %" PRIu64 " %s\n", pubkey->algorithm,
+ printf("Algorithm: %u %s\n", pubkey->algorithm,
vb1_crypto_name(pubkey->algorithm));
- printf("Key Version: %" PRIu64 "\n", pubkey->key_version);
+ printf("Key Version: %u\n", pubkey->key_version);
printf("Key sha1sum: %s\n",
- packed_key_sha1_string((struct vb2_packed_key *)pubkey));
- if (outfile) {
- if (0 != PublicKeyWrite(outfile, pubkey)) {
- fprintf(stderr,
- "vbutil_key: Error writing key copy\n");
- free(pubkey);
- return 1;
- }
+ packed_key_sha1_string(pubkey));
+ if (outfile &&
+ VB2_SUCCESS != vb2_write_packed_key(outfile, pubkey)) {
+ fprintf(stderr, "butil_key: Error writing key copy\n");
+ free(pubkey);
+ return 1;
}
free(pubkey);
return 0;
@@ -146,14 +143,11 @@ static int do_unpack(const char *infile, const char *outfile)
vb2_get_crypto_algorithm(privkey->hash_alg,
privkey->sig_alg);
printf("Algorithm: %u %s\n", alg, vb1_crypto_name(alg));
- if (outfile) {
- if (VB2_SUCCESS !=
- vb2_write_private_key(outfile, privkey)) {
- fprintf(stderr,
- "vbutil_key: Error writing key copy\n");
- free(privkey);
- return 1;
- }
+ if (outfile &&
+ VB2_SUCCESS != vb2_write_private_key(outfile, privkey)) {
+ fprintf(stderr,"vbutil_key: Error writing key copy\n");
+ free(privkey);
+ return 1;
}
free(privkey);
return 0;
diff --git a/futility/cmd_vbutil_keyblock.c b/futility/cmd_vbutil_keyblock.c
index 27624931..246616b8 100644
--- a/futility/cmd_vbutil_keyblock.c
+++ b/futility/cmd_vbutil_keyblock.c
@@ -225,14 +225,12 @@ static int Unpack(const char *infile, const char *datapubkey,
vb1_crypto_name(data_key->algorithm));
printf("Data key version: %u\n", data_key->key_version);
printf("Data key sha1sum: %s\n",
- packed_key_sha1_string((struct vb2_packed_key *)data_key));
+ packed_key_sha1_string(data_key));
- if (datapubkey) {
- if (0 != PublicKeyWrite(datapubkey, (VbPublicKey *)data_key)) {
- fprintf(stderr, "vbutil_keyblock:"
- " unable to write public key\n");
- return 1;
- }
+ if (datapubkey &&
+ VB2_SUCCESS != vb2_write_packed_key(datapubkey, data_key)) {
+ fprintf(stderr, "vbutil_keyblock: error writing public key\n");
+ return 1;
}
free(block);
diff --git a/futility/file_type_bios.c b/futility/file_type_bios.c
index 118b0aa3..ce6371d2 100644
--- a/futility/file_type_bios.c
+++ b/futility/file_type_bios.c
@@ -56,7 +56,6 @@ int ft_show_gbb(const char *name, uint8_t *buf, uint32_t len, void *data)
{
GoogleBinaryBlockHeader *gbb = (GoogleBinaryBlockHeader *)buf;
struct bios_state_s *state = (struct bios_state_s *)data;
- struct vb2_packed_key *pubkey;
BmpBlockHeader *bmp;
int retval = 0;
uint32_t maxlen = 0;
@@ -96,7 +95,8 @@ int ft_show_gbb(const char *name, uint8_t *buf, uint32_t len, void *data)
printf(" HWID: %s\n", buf + gbb->hwid_offset);
print_hwid_digest(gbb, " digest: ", "\n");
- pubkey = (struct vb2_packed_key *)(buf + gbb->rootkey_offset);
+ struct vb2_packed_key *pubkey =
+ (struct vb2_packed_key *)(buf + gbb->rootkey_offset);
if (packed_key_looks_ok(pubkey, gbb->rootkey_size)) {
if (state) {
state->rootkey.offset =
@@ -282,8 +282,9 @@ static int fmap_sign_fw_preamble(const char *name, uint8_t *buf, uint32_t len,
goto whatever;
}
- RSAPublicKey *rsa = PublicKeyToRSA((VbPublicKey *)&keyblock->data_key);
- if (!rsa) {
+ if (!packed_key_looks_ok(&keyblock->data_key,
+ keyblock->data_key.key_offset +
+ keyblock->data_key.key_size)) {
fprintf(stderr, "Warning: %s public key is invalid. "
"Signing the entire FW FMAP region...\n", name);
goto whatever;
@@ -424,13 +425,13 @@ static int sign_bios_at_end(struct bios_state_s *state)
sign_option.devkeyblock);
} else {
retval |= write_new_preamble(vblock_a, fw_a,
- sign_option.signprivate2,
+ sign_option.signprivate,
sign_option.keyblock);
}
/* FW B is always normal keys */
retval |= write_new_preamble(vblock_b, fw_b,
- sign_option.signprivate2,
+ sign_option.signprivate,
sign_option.keyblock);
diff --git a/futility/futility_options.h b/futility/futility_options.h
index 4739f04a..6ac95b12 100644
--- a/futility/futility_options.h
+++ b/futility/futility_options.h
@@ -33,9 +33,9 @@ struct show_option_s {
extern struct show_option_s show_option;
struct sign_option_s {
- struct vb2_private_key *signprivate2;
+ struct vb2_private_key *signprivate;
struct vb2_keyblock *keyblock;
- VbPublicKey *kernel_subkey;
+ struct vb2_packed_key *kernel_subkey;
struct vb2_private_key *devsignprivate;
struct vb2_keyblock *devkeyblock;
uint32_t version;
diff --git a/futility/vb1_helper.c b/futility/vb1_helper.c
index 2ec77501..314fd02e 100644
--- a/futility/vb1_helper.c
+++ b/futility/vb1_helper.c
@@ -502,17 +502,16 @@ int WriteSomeParts(const char *outfile,
/* Returns 0 on success */
int VerifyKernelBlob(uint8_t *kernel_blob,
uint64_t kernel_size,
- VbPublicKey *signpub_key,
+ struct vb2_packed_key *signpub_key,
const char *keyblock_outfile,
uint64_t min_version)
{
- RSAPublicKey *rsa;
int rv = -1;
uint64_t vmlinuz_header_size = 0;
uint64_t vmlinuz_header_address = 0;
- static uint8_t workbuf[VB2_WORKBUF_RECOMMENDED_SIZE];
- static struct vb2_workbuf wb;
+ uint8_t workbuf[VB2_KERNEL_WORKBUF_RECOMMENDED_SIZE];
+ struct vb2_workbuf wb;
vb2_workbuf_init(&wb, workbuf, sizeof(workbuf));
if (signpub_key) {
@@ -585,15 +584,18 @@ int VerifyKernelBlob(uint8_t *kernel_blob,
goto done;
}
- rsa = PublicKeyToRSA((VbPublicKey *)data_key);
- if (!rsa) {
+ struct vb2_public_key pubkey;
+ if (VB2_SUCCESS !=
+ vb2_unpack_key(&pubkey, (uint8_t *)data_key,
+ data_key->key_offset + data_key->key_size)) {
fprintf(stderr, "Error parsing data key.\n");
goto done;
}
/* Verify preamble */
- if (0 != VerifyKernelPreamble(g_preamble,
- g_preamble->preamble_size, rsa)) {
+ if (VB2_SUCCESS != vb2_verify_kernel_preamble(
+ (struct vb2_kernel_preamble *)g_preamble,
+ g_preamble->preamble_size, &pubkey, &wb)) {
fprintf(stderr, "Error verifying preamble.\n");
goto done;
}
@@ -642,8 +644,10 @@ int VerifyKernelBlob(uint8_t *kernel_blob,
}
/* Verify body */
- if (0 != VerifyData(kernel_blob, kernel_size,
- &g_preamble->body_signature, rsa)) {
+ if (VB2_SUCCESS !=
+ vb2_verify_data(kernel_blob, kernel_size,
+ (struct vb2_signature *)&g_preamble->body_signature,
+ &pubkey, &wb)) {
fprintf(stderr, "Error verifying kernel body.\n");
goto done;
}
@@ -749,17 +753,14 @@ uint8_t *CreateKernelBlob(uint8_t *vmlinuz_buf, uint64_t vmlinuz_size,
enum futil_file_type ft_recognize_vblock1(uint8_t *buf, uint32_t len)
{
- int rv;
-
- uint8_t workbuf[VB2_WORKBUF_RECOMMENDED_SIZE];
+ uint8_t workbuf[VB2_KERNEL_WORKBUF_RECOMMENDED_SIZE];
struct vb2_workbuf wb;
vb2_workbuf_init(&wb, workbuf, sizeof(workbuf));
/* Vboot 2.0 signature checks destroy the buffer, so make a copy */
uint8_t *buf2 = malloc(len);
memcpy(buf2, buf, len);
-
- struct vb2_keyblock *keyblock = (struct vb2_keyblock *)buf;
+ struct vb2_keyblock *keyblock = (struct vb2_keyblock *)buf2;
if (VB2_SUCCESS != vb2_verify_keyblock_hash(keyblock, len, &wb)) {
free(buf2);
return FILE_TYPE_UNKNOWN;
@@ -780,18 +781,26 @@ enum futil_file_type ft_recognize_vblock1(uint8_t *buf, uint32_t len)
/* Followed by firmware preamble too? */
struct vb2_fw_preamble *pre2 = (struct vb2_fw_preamble *)(buf2 + more);
- rv = vb2_verify_fw_preamble(pre2, len - more, &data_key, &wb);
- free(buf2);
- if (VB2_SUCCESS == rv)
+ if (VB2_SUCCESS ==
+ vb2_verify_fw_preamble(pre2, len - more, &data_key, &wb)) {
+ free(buf2);
return FILE_TYPE_FW_PREAMBLE;
+ }
+
+ /* Recopy since firmware preamble check destroyed the buffer */
+ memcpy(buf2, buf, len);
/* Or maybe kernel preamble? */
- RSAPublicKey *rsa = PublicKeyToRSA((VbPublicKey *)&keyblock->data_key);
- VbKernelPreambleHeader *kern_preamble =
- (VbKernelPreambleHeader *)(buf + more);
- if (VBOOT_SUCCESS ==
- VerifyKernelPreamble(kern_preamble, len - more, rsa))
+ struct vb2_kernel_preamble *kern_preamble =
+ (struct vb2_kernel_preamble *)(buf2 + more);
+ if (VB2_SUCCESS ==
+ vb2_verify_kernel_preamble(kern_preamble, len - more,
+ &data_key, &wb)) {
+ free(buf2);
return FILE_TYPE_KERN_PREAMBLE;
+ }
+
+ free(buf2);
/* No, just keyblock */
return FILE_TYPE_KEYBLOCK;
diff --git a/futility/vb1_helper.h b/futility/vb1_helper.h
index 1c59da53..e8a4f5d1 100644
--- a/futility/vb1_helper.h
+++ b/futility/vb1_helper.h
@@ -53,7 +53,7 @@ int UpdateKernelBlobConfig(uint8_t *kblob_data, uint64_t kblob_size,
int VerifyKernelBlob(uint8_t *kernel_blob,
uint64_t kernel_size,
- VbPublicKey *signpub_key,
+ struct vb2_packed_key *signpub_key,
const char *keyblock_outfile,
uint64_t min_version);