keyfork mnemonic generate: userid equivalency, rename provisioner cert_output to output
This commit is contained in:
parent
db19b30bfe
commit
723194fdd7
|
@ -224,14 +224,18 @@ pub enum MnemonicSubcommands {
|
||||||
/// of the encryption will be written to `encrypted.asc`. Otherwise, the
|
/// of the encryption will be written to `encrypted.asc`. Otherwise, the
|
||||||
/// default behavior is to write the certificate to a file named after the certificate's
|
/// default behavior is to write the certificate to a file named after the certificate's
|
||||||
/// fingerprint. If either output file already exists, it will not be overwritten, and the
|
/// fingerprint. If either output file already exists, it will not be overwritten, and the
|
||||||
/// command will exit unsuccessfully.
|
/// command will exit unsuccessfully. This functionality must happen regardless if a
|
||||||
|
/// provisioner output is specified, as the certificate is then used to encrypt the
|
||||||
|
/// mnemonic.
|
||||||
///
|
///
|
||||||
/// Additionally, when given the `account=` option (which must match the `account=` option
|
/// Additionally, when given the `account=` option (which must match the `account=` option
|
||||||
/// of the relevant provisioner), the given account will be used instead of the default
|
/// of the relevant provisioner), the given account will be used instead of the default
|
||||||
/// account of 0.
|
/// account of 0.
|
||||||
///
|
///
|
||||||
/// Because a new OpenPGP key needs to be created, a User ID can also be supplied, using
|
/// Because a new OpenPGP cert needs to be created, a User ID can also be supplied, using
|
||||||
/// the option `userid=<your User ID>`. It can contain any characters that are not a comma.
|
/// the option `userid=<your User ID>`. It can contain any characters that are not a comma.
|
||||||
|
/// If any other operation generating an OpenPGP key has a `userid=` field, and this
|
||||||
|
/// operation doesn't, that User ID will be used instead.
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
encrypt_to_self: Option<ValueWithOptions<PathBuf>>,
|
encrypt_to_self: Option<ValueWithOptions<PathBuf>>,
|
||||||
|
|
||||||
|
@ -241,6 +245,17 @@ pub enum MnemonicSubcommands {
|
||||||
/// Additional arguments, such as the amount of hardware to provision and the
|
/// Additional arguments, such as the amount of hardware to provision and the
|
||||||
/// account to use when deriving, can be specified by using (for example)
|
/// account to use when deriving, can be specified by using (for example)
|
||||||
/// `--provision openpgp-card,count=2,account=1`.
|
/// `--provision openpgp-card,count=2,account=1`.
|
||||||
|
///
|
||||||
|
/// Provisioners may output their public key, if necessary. The file path may be chosen
|
||||||
|
/// based on the provided `output` field, or automatically determined based on the content
|
||||||
|
/// of the key, such as an OpenPGP fingerprint or a public key hash. If automatically
|
||||||
|
/// generated, the filename will be printed.
|
||||||
|
///
|
||||||
|
/// If the OpenPGP Card provisioner is selected, because a new OpenPGP cert needs to be
|
||||||
|
/// created, a User ID can also be supplied, using the option `userid=<your User ID>`. It
|
||||||
|
/// can contain any characters that are not a comma. If any other operation generating an
|
||||||
|
/// OpenPGP key has a `userid=` field, and this operation doesn't, that User ID will be
|
||||||
|
/// used instead.
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
provision: Option<ValueWithOptions<provision::Provisioner>>,
|
provision: Option<ValueWithOptions<provision::Provisioner>>,
|
||||||
},
|
},
|
||||||
|
@ -578,7 +593,18 @@ impl MnemonicSubcommands {
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(encrypt_to_self) = encrypt_to_self {
|
if let Some(encrypt_to_self) = encrypt_to_self {
|
||||||
do_encrypt_to_self(&mnemonic, &encrypt_to_self.inner, &encrypt_to_self.values)?;
|
let mut values = encrypt_to_self.values.clone();
|
||||||
|
// If we have a userid from `provision` but not one here, use that one.
|
||||||
|
if let Some(provision) = provision {
|
||||||
|
if matches!(&provision.inner, provision::Provisioner::OpenPGPCard(_))
|
||||||
|
&& !values.contains_key("userid")
|
||||||
|
{
|
||||||
|
if let Some(userid) = provision.values.get("userid") {
|
||||||
|
values.insert(String::from("userid"), userid.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
do_encrypt_to_self(&mnemonic, &encrypt_to_self.inner, &values)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(provisioner) = provision {
|
if let Some(provisioner) = provision {
|
||||||
|
@ -589,12 +615,23 @@ impl MnemonicSubcommands {
|
||||||
// key output.
|
// key output.
|
||||||
//
|
//
|
||||||
// We use the atypical `_skip_cert_output` field here to denote an automatic
|
// We use the atypical `_skip_cert_output` field here to denote an automatic
|
||||||
// marking to skip the cert output. However, the `cert_output` field will take
|
// marking to skip the cert output. However, the `output` field will take
|
||||||
// priority, since it can only be manually set by the user.
|
// priority, since it can only be manually set by the user.
|
||||||
let mut values = provisioner.values.clone();
|
let mut values = provisioner.values.clone();
|
||||||
if encrypt_to_self.is_some() {
|
if let Some(encrypt_to_self) = encrypt_to_self {
|
||||||
|
if !values.contains_key("output") {
|
||||||
values.insert(String::from("_skip_cert_output"), String::from("1"));
|
values.insert(String::from("_skip_cert_output"), String::from("1"));
|
||||||
}
|
}
|
||||||
|
// If we have a userid from `encrypt_to_self` but not one here, use that
|
||||||
|
// one.
|
||||||
|
if matches!(&provisioner.inner, provision::Provisioner::OpenPGPCard(_))
|
||||||
|
&& !values.contains_key("userid")
|
||||||
|
{
|
||||||
|
if let Some(userid) = encrypt_to_self.values.get("userid") {
|
||||||
|
values.insert(String::from("userid"), userid.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
do_provision(&mnemonic, &provisioner.inner, &values)?;
|
do_provision(&mnemonic, &provisioner.inner, &values)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -85,23 +85,21 @@ impl ProvisionExec for OpenPGPCard {
|
||||||
KeyFlags::empty().set_authentication(),
|
KeyFlags::empty().set_authentication(),
|
||||||
];
|
];
|
||||||
|
|
||||||
// NOTE: This User ID doesn't have meaningful context on the card.
|
let userid = match provisioner.metadata.as_ref().and_then(|m| m.get("userid")) {
|
||||||
// To give it a reasonable name, use `keyfork derive openpgp` or some other system that
|
Some(userid) => UserID::from(userid.as_str()),
|
||||||
// generates the OpenPGP certificate.
|
None => UserID::from("Keyfork-Provisioned Key"),
|
||||||
let userid = UserID::from("Keyfork-Provisioned Key");
|
};
|
||||||
let cert = keyfork_derive_openpgp::derive(xprv.clone(), &subkeys, &userid)?;
|
let cert = keyfork_derive_openpgp::derive(xprv.clone(), &subkeys, &userid)?;
|
||||||
|
|
||||||
// cert_output is never automatically set, but _skip_cert_output is, so we bypass the
|
|
||||||
// automatically generated _skip_cert_output
|
|
||||||
if !provisioner
|
if !provisioner
|
||||||
.metadata
|
.metadata
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.is_some_and(|m| m.contains_key("_skip_cert_output") && !m.contains_key("cert_output"))
|
.is_some_and(|m| m.contains_key("_skip_cert_output"))
|
||||||
{
|
{
|
||||||
let cert_output = match provisioner
|
let cert_output = match provisioner
|
||||||
.metadata
|
.metadata
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(|m| m.get("cert_output"))
|
.and_then(|m| m.get("output"))
|
||||||
{
|
{
|
||||||
Some(cert_output) => PathBuf::from(cert_output),
|
Some(cert_output) => PathBuf::from(cert_output),
|
||||||
None => {
|
None => {
|
||||||
|
|
Loading…
Reference in New Issue