Skip to content

Add constraint parsing to RusticaAgent#68

Open
obelisk wants to merge 2 commits intodevelopfrom
msg_25_again
Open

Add constraint parsing to RusticaAgent#68
obelisk wants to merge 2 commits intodevelopfrom
msg_25_again

Conversation

@obelisk
Copy link
Owner

@obelisk obelisk commented Mar 10, 2026

We didn't support adding SK-* keys to RusticaAgent due to the use of the AddIdentityConstrained message type.

This adds support for that and correctly parses the constraints but as of now, doesn't implement the spec other than rejecting keys with constraints it doesn't understand

@obelisk obelisk requested a review from Copilot March 10, 2026 23:15
@obelisk obelisk self-assigned this Mar 10, 2026
@obelisk obelisk added the enhancement New feature or request label Mar 10, 2026
@obelisk obelisk requested a review from timweri March 10, 2026 23:15
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds parsing support for SSH2_AGENTC_ADD_ID_CONSTRAINED so RusticaAgent can accept SK-* keys delivered via the constrained add-identity message, including basic constraint decoding.

Changes:

  • Bump sshcerts to 0.14.1 to support the needed parsing APIs.
  • Add constraint parsing (Lifetime, Confirm, Extension) and plumb constrained-add requests through the agent handler.
  • Introduce a new constraints module and a new AddIdentityConstrained request flow.

Reviewed changes

Copilot reviewed 7 out of 8 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
rustica/Cargo.toml Bumps sshcerts dependency version used by the rustica crate.
rustica-agent/Cargo.toml Bumps sshcerts dependency version used by rustica-agent.
Cargo.lock Locks updated sshcerts version/checksum.
rustica-agent/src/sshagent/protocol.rs Parses AddIdConstrained messages into a new request variant and reads constraints.
rustica-agent/src/sshagent/mod.rs Exposes new constraints module and re-exports adjusted items.
rustica-agent/src/sshagent/handler.rs Extends SshAgentHandler with add_identity_constrained and dispatches it.
rustica-agent/src/sshagent/constraints.rs New constraint parser and Constraint enum.
rustica-agent/src/lib.rs Implements add_identity_constrained for the primary handler.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 7 out of 8 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

) -> Result<Response, AgentError> {
trace!("Add Identity Constrained call");
if !constraints.is_empty() {
trace!("Key is being added with constraints");
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add_identity_constrained currently accepts and stores the key even when constraints is non-empty, effectively ignoring lifetime/confirm/extension constraints. This can widen key usage vs what the client requested (e.g., confirm-required or limited lifetime), which is a security footgun. Either enforce the supported constraints here (or store them alongside the key for later enforcement), or reject non-empty constraints until enforcement is implemented (return Response::Failure).

Suggested change
trace!("Key is being added with constraints");
trace!("Key is being added with constraints, which are not currently supported");
// Until constraints are properly enforced or stored for later enforcement,
// reject attempts to add constrained identities to avoid silently widening key usage.
return Ok(Response::Failure);

Copilot uses AI. Check for mistakes.
Comment on lines +17 to +18
constraints: Vec<Constraint>,
) -> HandleResult<Response>;
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding a new required method to the public SshAgentHandler trait is a breaking change for any external implementers. Consider providing a default implementation for add_identity_constrained (e.g., delegate to add_identity or return Response::Failure) to preserve compatibility, or bump the crate version appropriately if this is intended to be breaking.

Suggested change
constraints: Vec<Constraint>,
) -> HandleResult<Response>;
_constraints: Vec<Constraint>,
) -> HandleResult<Response> {
// Default behavior: ignore constraints and treat this as a regular identity add.
self.add_identity(key).await
}

Copilot uses AI. Check for mistakes.
Comment on lines 3 to +7
mod agent;
mod protocol;
mod handler;
pub mod constraints;
pub mod error;
mod handler;
mod protocol;
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Making the entire constraints module public exposes internal parsing helpers (parse_constraints) as part of the crate API. If consumers only need the Constraint type (e.g., to implement SshAgentHandler), consider keeping the module private and re-exporting Constraint from sshagent (and making parse_constraints pub(crate)), which reduces public API surface while still allowing the type to be referenced.

Copilot uses AI. Check for mistakes.
.map_err(|_| "Failed to read bytes for extension data")?;
constraints.push(Constraint::Extension(ext_name, ext_data));
}
_ => return Err("Unknown constraint type".into()),
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

parse_constraints returns a generic "Unknown constraint type" error without including the actual byte value, which makes debugging wire-compat issues harder. Consider incorporating the constraint_type value in the error details (and possibly the offset) so logs clearly show what was rejected.

Suggested change
_ => return Err("Unknown constraint type".into()),
_ => {
let offset = reader.get_offset().saturating_sub(1);
return Err(format!(
"Unknown constraint type {} at offset {}",
constraint_type, offset
)
.into());
}

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants