Add bearer challenge-response proofs
This commit is contained in:
parent
43433dbf1d
commit
72cd018a3e
11 changed files with 444 additions and 10 deletions
|
|
@ -24,7 +24,7 @@ use geth_kv::{KvEntry, KvResource, KvSyncEntry};
|
|||
use geth_pipe::{PipeConnection, PipeListener};
|
||||
use geth_pubsub::PubsubMessage;
|
||||
use geth_resource::ResourceDescriptor;
|
||||
use geth_secrets::{BearerAccess, ResourceMasterSecret};
|
||||
use geth_secrets::{BearerAccess, BearerChallenge, BearerProof, ResourceMasterSecret};
|
||||
use geth_ssh_identity::{
|
||||
SshCertApproval, SshCertKind, SshCertRequest, SshCertRequestStatus, SshCertificateRecord,
|
||||
SshRevocationEntry, SshRevocationExportFormat, SshRevocationKind, build_ssh_cert_sign_command,
|
||||
|
|
@ -3011,6 +3011,114 @@ pub fn handle_request(
|
|||
ControlRequest::SecretBearerList => Ok(ControlResponse::SecretBearerList {
|
||||
access: load_bearer_access(&store)?,
|
||||
}),
|
||||
ControlRequest::SecretBearerChallenge {
|
||||
resource,
|
||||
capabilities,
|
||||
} => {
|
||||
ensure_resource_exists(&store, &resource)?;
|
||||
let capabilities = capabilities
|
||||
.into_iter()
|
||||
.map(Capability::new)
|
||||
.collect::<Vec<_>>();
|
||||
geth_secrets::validate_bearer_capabilities(&capabilities)?;
|
||||
let issued_at = UnixMillis(geth_store::now_ms());
|
||||
let nonce = geth_crypto::blake3_hex(
|
||||
format!("{}\0{}\0{}", node.agent_id, resource, issued_at.0).as_bytes(),
|
||||
);
|
||||
Ok(ControlResponse::SecretBearerChallenge {
|
||||
challenge: BearerChallenge {
|
||||
resource: ResourceId::new(resource),
|
||||
capabilities,
|
||||
nonce,
|
||||
issued_at,
|
||||
},
|
||||
})
|
||||
}
|
||||
ControlRequest::SecretBearerProve {
|
||||
secret,
|
||||
resource,
|
||||
capabilities,
|
||||
nonce,
|
||||
} => {
|
||||
ensure_resource_exists(&store, &resource)?;
|
||||
let capabilities = capabilities
|
||||
.into_iter()
|
||||
.map(Capability::new)
|
||||
.collect::<Vec<_>>();
|
||||
geth_secrets::validate_bearer_capabilities(&capabilities)?;
|
||||
let secret = geth_types::SecretId::new(secret);
|
||||
let resource = ResourceId::new(resource);
|
||||
let response = geth_secrets::bearer_response(&secret, &resource, &capabilities, &nonce);
|
||||
Ok(ControlResponse::SecretBearerProof {
|
||||
proof: BearerProof {
|
||||
secret,
|
||||
resource,
|
||||
capabilities,
|
||||
nonce,
|
||||
response,
|
||||
},
|
||||
})
|
||||
}
|
||||
ControlRequest::SecretBearerVerify {
|
||||
secret,
|
||||
resource,
|
||||
capabilities,
|
||||
nonce,
|
||||
response,
|
||||
} => {
|
||||
ensure_resource_exists(&store, &resource)?;
|
||||
let requested_capabilities = capabilities
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(Capability::new)
|
||||
.collect::<Vec<_>>();
|
||||
geth_secrets::validate_bearer_capabilities(&requested_capabilities)?;
|
||||
let secret_id = geth_types::SecretId::new(secret.clone());
|
||||
let resource_id = ResourceId::new(resource.clone());
|
||||
let access = load_bearer_access(&store)?.into_iter().find(|access| {
|
||||
access.secret == secret_id
|
||||
&& access.resource == resource_id
|
||||
&& access
|
||||
.expires_at
|
||||
.is_none_or(|expires_at| expires_at.0 >= geth_store::now_ms())
|
||||
});
|
||||
let (verified, reason) = if let Some(access) = access {
|
||||
let has_capabilities = requested_capabilities
|
||||
.iter()
|
||||
.all(|capability| access.capabilities.contains(capability));
|
||||
if !has_capabilities {
|
||||
(
|
||||
false,
|
||||
"bearer secret lacks requested capabilities".to_owned(),
|
||||
)
|
||||
} else if geth_secrets::verify_bearer_response(
|
||||
&secret_id,
|
||||
&resource_id,
|
||||
&requested_capabilities,
|
||||
&nonce,
|
||||
&response,
|
||||
) {
|
||||
(
|
||||
true,
|
||||
"bearer proof verified for resource-scoped capabilities".to_owned(),
|
||||
)
|
||||
} else {
|
||||
(
|
||||
false,
|
||||
"bearer proof response did not match challenge".to_owned(),
|
||||
)
|
||||
}
|
||||
} else {
|
||||
(false, "bearer access not found or expired".to_owned())
|
||||
};
|
||||
Ok(ControlResponse::SecretBearerVerified {
|
||||
secret,
|
||||
resource,
|
||||
capabilities,
|
||||
verified,
|
||||
reason,
|
||||
})
|
||||
}
|
||||
ControlRequest::SecretBearerRevoke { resource, secret } => {
|
||||
ensure_resource_exists(&store, &resource)?;
|
||||
let created_at = UnixMillis(geth_store::now_ms());
|
||||
|
|
|
|||
Loading…
Reference in a new issue