Extract reusable keychain sigchain model
This commit is contained in:
parent
5b2c30f817
commit
4013c868aa
11 changed files with 938 additions and 20 deletions
|
|
@ -403,7 +403,13 @@ fn initialize_owner_keychain(
|
|||
ops.push(KeychainOp {
|
||||
id: generated_keychain_op_id("admin-key-add", admin_key.as_str(), now),
|
||||
created_at: now,
|
||||
kind: KeychainOpKind::AdminKeyAdd { key: admin_key },
|
||||
kind: KeychainOpKind::AdminKeyAdd {
|
||||
key: admin_key,
|
||||
public_key: Some(public_key.trim().to_owned()),
|
||||
principal: Some("admin".to_owned()),
|
||||
valid_after_ms: None,
|
||||
valid_before_ms: None,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -3389,7 +3395,7 @@ async fn keychain_sync_from_peer_since(
|
|||
.iter()
|
||||
.filter(|signature| {
|
||||
if !trusted_admins.contains(&signature.signer)
|
||||
|| !keychain_signature_uses_claimed_key(signature)
|
||||
|| !geth_keychain::signature_uses_claimed_key(signature)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
@ -7578,7 +7584,13 @@ pub fn handle_request(
|
|||
let op = KeychainOp {
|
||||
id: generated_keychain_op_id("admin-key-add", admin_key.as_str(), created_at),
|
||||
created_at,
|
||||
kind: KeychainOpKind::AdminKeyAdd { key: admin_key },
|
||||
kind: KeychainOpKind::AdminKeyAdd {
|
||||
key: admin_key,
|
||||
public_key: Some(public_key.trim().to_owned()),
|
||||
principal: Some("admin".to_owned()),
|
||||
valid_after_ms: None,
|
||||
valid_before_ms: None,
|
||||
},
|
||||
};
|
||||
store_keychain_op(&store, &op)?;
|
||||
ops.push(op);
|
||||
|
|
@ -7608,6 +7620,81 @@ pub fn handle_request(
|
|||
nodes: view.nodes.len(),
|
||||
}))
|
||||
}
|
||||
ControlRequest::KeychainAdminAdd {
|
||||
admin_key_path,
|
||||
signing_key_path,
|
||||
principal,
|
||||
valid_after_ms,
|
||||
valid_before_ms,
|
||||
} => {
|
||||
let public_key = std::fs::read_to_string(&admin_key_path)?;
|
||||
let admin_key = KeyId::new(ssh_public_key_fingerprint(&public_key));
|
||||
let created_at = UnixMillis(geth_store::now_ms());
|
||||
let op = KeychainOp {
|
||||
id: generated_keychain_op_id("admin-key-add", admin_key.as_str(), created_at),
|
||||
created_at,
|
||||
kind: KeychainOpKind::AdminKeyAdd {
|
||||
key: admin_key,
|
||||
public_key: Some(public_key.trim().to_owned()),
|
||||
principal: principal.or_else(|| Some("admin".to_owned())),
|
||||
valid_after_ms,
|
||||
valid_before_ms,
|
||||
},
|
||||
};
|
||||
let signatures = store_and_sign_keychain_ops(
|
||||
&store,
|
||||
node,
|
||||
std::slice::from_ref(&op),
|
||||
Some(&signing_key_path),
|
||||
None,
|
||||
)?;
|
||||
Ok(ControlResponse::KeychainAdminUpdated {
|
||||
op,
|
||||
signatures,
|
||||
note: "recorded signed admin key addition in the keychain sigchain".to_owned(),
|
||||
})
|
||||
}
|
||||
ControlRequest::KeychainAdminRevoke {
|
||||
key,
|
||||
signing_key_path,
|
||||
admin_key_path,
|
||||
} => {
|
||||
let created_at = UnixMillis(geth_store::now_ms());
|
||||
let op = KeychainOp {
|
||||
id: generated_keychain_op_id("admin-key-revoke", &key, created_at),
|
||||
created_at,
|
||||
kind: KeychainOpKind::AdminKeyRevoke {
|
||||
key: KeyId::new(key),
|
||||
},
|
||||
};
|
||||
let signatures = store_and_sign_keychain_ops(
|
||||
&store,
|
||||
node,
|
||||
std::slice::from_ref(&op),
|
||||
Some(&signing_key_path),
|
||||
admin_key_path.as_deref(),
|
||||
)?;
|
||||
Ok(ControlResponse::KeychainAdminUpdated {
|
||||
op,
|
||||
signatures,
|
||||
note: "recorded signed admin key revocation in the keychain sigchain".to_owned(),
|
||||
})
|
||||
}
|
||||
ControlRequest::KeychainAllowedSigners => {
|
||||
let entries = geth_keychain::allowed_signers(
|
||||
&load_keychain_ops(&store)?,
|
||||
&load_keychain_signatures(&store)?,
|
||||
);
|
||||
let allowed_signers = geth_keychain::render_allowed_signers(&entries);
|
||||
Ok(ControlResponse::KeychainAllowedSigners {
|
||||
entries,
|
||||
allowed_signers,
|
||||
note: "derived from active AdminKeyAdd/AdminKeyRevoke operations; compatible with ssh-keygen -Y allowed_signers format".to_owned(),
|
||||
})
|
||||
}
|
||||
ControlRequest::KeychainVerify => Ok(ControlResponse::KeychainVerified {
|
||||
report: verify_keychain_sigchain_with_ssh(&store, node)?,
|
||||
}),
|
||||
ControlRequest::NodeList => {
|
||||
let view = geth_keychain::reduce_keychain_ops(&load_keychain_ops(&store)?);
|
||||
Ok(ControlResponse::NodeList {
|
||||
|
|
@ -10414,6 +10501,26 @@ fn store_keychain_op(store: &Store, op: &KeychainOp) -> Result<(), NodeError> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn verify_keychain_sigchain_with_ssh(
|
||||
store: &Store,
|
||||
node: &LocalNode,
|
||||
) -> Result<geth_keychain::KeychainSigchainReport, NodeError> {
|
||||
let ops = load_keychain_ops(store)?;
|
||||
let signatures = load_keychain_signatures(store)?;
|
||||
Ok(geth_keychain::verify_sigchain(
|
||||
&ops,
|
||||
&signatures,
|
||||
&|op, signature| {
|
||||
verify_keychain_signature_with_ssh(
|
||||
node,
|
||||
op,
|
||||
&stored_keychain_signature_from_signature(signature),
|
||||
)
|
||||
.unwrap_or(false)
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
fn store_and_sign_keychain_ops(
|
||||
store: &Store,
|
||||
node: &LocalNode,
|
||||
|
|
@ -10519,10 +10626,6 @@ fn stored_keychain_signature_from_signature(
|
|||
}
|
||||
}
|
||||
|
||||
fn keychain_signature_uses_claimed_key(signature: &KeychainOpSignature) -> bool {
|
||||
KeyId::new(ssh_public_key_fingerprint(&signature.signer_public_key)) == signature.signer
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
||||
struct KeychainSignatureStatus {
|
||||
total: usize,
|
||||
|
|
@ -10614,11 +10717,12 @@ fn verify_keychain_signature_with_ssh(
|
|||
}
|
||||
|
||||
fn load_keychain_ops(store: &Store) -> Result<Vec<KeychainOp>, NodeError> {
|
||||
store
|
||||
let ops = store
|
||||
.list_keychain_ops()?
|
||||
.into_iter()
|
||||
.map(|stored| serde_json::from_str(&stored.op_json).map_err(NodeError::from))
|
||||
.collect()
|
||||
.map(|stored| serde_json::from_str::<KeychainOp>(&stored.op_json).map_err(NodeError::from))
|
||||
.collect::<Result<Vec<_>, NodeError>>()?;
|
||||
Ok(geth_keychain::sorted_keychain_ops(ops))
|
||||
}
|
||||
|
||||
fn load_keychain_signatures(store: &Store) -> Result<Vec<KeychainOpSignature>, NodeError> {
|
||||
|
|
|
|||
Loading…
Reference in a new issue