Skip to content

Add Md5AuthString type - #96

Merged
taspelund merged 2 commits into
mainfrom
trey/md5-auth-string
Sep 1, 2026
Merged

Add Md5AuthString type#96
taspelund merged 2 commits into
mainfrom
trey/md5-auth-string

Conversation

@taspelund

Copy link
Copy Markdown
Contributor

Adds wrapper type for MD5 passwords used with TCP (RFC 2385). Md5AuthString enforces constraints around length (1-80 bytes, inclusive) as well as content (printable ASCII), with proper Errors and memory zeroization.

Adds wrapper type for MD5 passwords used with TCP (RFC 2385).
Md5AuthString enforces constraints around length (1-80 bytes, inclusive)
as well as content (printable ASCII), with proper Errors and memory
zeroization.

Signed-off-by: Trey Aspelund <trey@oxidecomputer.com>
@taspelund taspelund self-assigned this Aug 30, 2026
@taspelund taspelund added the rust Pull requests that update rust code label Aug 30, 2026
@ahl

ahl commented Aug 31, 2026

Copy link
Copy Markdown
Collaborator

Before I take a look, can you explain the purpose of zeroize in here?

@taspelund

Copy link
Copy Markdown
Contributor Author

Before I take a look, can you explain the purpose of zeroize in here?

Since the type is basically a wrapper on a password/secret, the idea was to add a little bit of extra security in the sense that the memory where the key was stored gets zeroed on drop. I don't feel super strongly about having it in the type, but zeroize is a small no_std crate and doesn't blow up the dependency graph by more than 1 dep, so I thought I'd see what folks think

Comment thread src/md5.rs Outdated
}
}

impl ZeroizeOnDrop for Md5AuthString {}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Worth a comment here that the contract this marker implies is maintained by Md5AuthString containing a Zeroizing<String> as its sole member. Perhaps also worth a comment at the Md5AuthString definition that if the data structure is changed, we need to either make sure that ZeroizeOnDrop is maintained or remove the marker.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good call, although I did you one better. Zeroize has a zeroize_derive feature that allows the trait to be derived rather than implemented. So I've converted over to using that, since it will cause compilation failures if all members of the product type don't also implement ZeroizeOnDrop.
e.g.

error[E0599]: the method `zeroize_or_on_drop` exists for mutable reference `&mut Instant`,
              but its trait bounds were not satisfied
 16 | #[derive(Clone, Eq, PartialEq, ZeroizeOnDrop)]
    |                                ^^^^^^^^^^^^^
    = note: the following trait bounds were not satisfied:
            `Instant: Zeroize`
    = note: this error originates in the derive macro `ZeroizeOnDrop`

Signed-off-by: Trey Aspelund <trey@oxidecomputer.com>
@taspelund
taspelund merged commit 0cdcffd into main Sep 1, 2026
14 checks passed
@taspelund
taspelund deleted the trey/md5-auth-string branch September 1, 2026 20:24

@ahl ahl left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think we should leave out zeroize. I don't see how it would be useful since the contained data does need to flow somewhere, and I don't think we're overly careful about removing every copy from memory. I would love to hear if you disagree.

Comment thread src/md5.rs
Comment on lines +12 to +15
/// The [`Debug`](std::fmt::Debug) implementation redacts the key, and its
/// allocation is zeroized when the value is dropped. Converting it into a
/// [`String`] transfers responsibility for zeroizing that allocation to the
/// caller. Its serialized representation contains the key as a plain string.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
/// The [`Debug`](std::fmt::Debug) implementation redacts the key, and its
/// allocation is zeroized when the value is dropped. Converting it into a
/// [`String`] transfers responsibility for zeroizing that allocation to the
/// caller. Its serialized representation contains the key as a plain string.
/// The [`Debug`](std::fmt::Debug) implementation redacts the key, and its
/// allocation is zeroed when the value is dropped. Converting it into a
/// [`String`] should therefore be done with caution since no zeroing may occur.

This raises a question for me. Where are we using this type where we are ensuring that places where the string occurs are zeroed? For example, if this is ever formatted into a query string or POST body by progenitor we're almost certainly not zeroing it. Is this even useful at all?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Currently this type isn't used anywhere, but the intention is to integrate it into the mgd API as an optional parameter for BGP peers as a replacement for the current raw String. The flow of this data currently is that it comes in via dropshot, gets stored in a config struct owned by a per BGP peer, and that data is copied out when we make a call into libnet to interact with a PF_KEY socket. I don't believe the libnet type uses zeroize, but that could always be updated to match.

I'm not as familiar with the dropshot side of things or what would be needed to provide similar zeroing.

As I said before, I'm not so strongly opinionated here as to say zeroing is a must. I would be okay removing it if the consensus is that the utility is limited / non-existent.

Comment thread src/md5.rs
pub const MAX_LEN: usize = 80;

/// Creates an MD5 authentication string after validating its contents.
pub fn new(source: String) -> Result<Self, Md5AuthStringError> {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

do we prefer new to TryFrom?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Not particularly. I'd lean towards having both over just one though.

Comment thread src/md5.rs
Comment on lines +52 to +53
/// Returns the underlying string, transferring responsibility for
/// zeroizing it to the caller.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
/// Returns the underlying string, transferring responsibility for
/// zeroizing it to the caller.
/// Returns the underlying string, transferring responsibility for
/// zeroing it to the caller.

Comment thread src/md5.rs
string: Some(Box::new(schemars::schema::StringValidation {
max_length: Some(Self::MAX_LEN as u32),
min_length: Some(1),
pattern: Some(r"^[ -~]+$".to_string()),

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

definitely non-obvious and needs a comment

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

rust Pull requests that update rust code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants