Skip to content

ssh-key: allow u64::MAX as "no expiry" sentinel in UnixTime - #504

Merged
tarcieri merged 1 commit into
RustCrypto:masterfrom
gvz:master
May 10, 2026
Merged

ssh-key: allow u64::MAX as "no expiry" sentinel in UnixTime#504
tarcieri merged 1 commit into
RustCrypto:masterfrom
gvz:master

Conversation

@gvz

@gvz gvz commented May 8, 2026

Copy link
Copy Markdown
Contributor

OpenSSH PROTOCOL.certkeys specifies that valid_before=0xffffffffffffffff (u64::MAX) means the certificate never expires. Previously UnixTime::new rejected this value because it exceeds MAX_SECS (i64::MAX), causing Certificate parsing to fail for any cert generated without an explicit validity window (e.g. ssh-keygen -s ca -h key.pub without -V).

Add FOREVER_SECS=u64::MAX constant. In new(), cap its SystemTime representation at MAX_SECS to keep a valid SystemTime while preserving the raw secs value for round-trip encoding correctness.

Fixes: #503

OpenSSH PROTOCOL.certkeys specifies that valid_before=0xffffffffffffffff
(u64::MAX) means the certificate never expires. Previously UnixTime::new
rejected this value because it exceeds MAX_SECS (i64::MAX), causing
Certificate parsing to fail for any cert generated without an explicit
validity window (e.g. ssh-keygen -s ca -h key.pub without -V).

Add FOREVER_SECS=u64::MAX constant. In new(), cap its SystemTime
representation at MAX_SECS to keep a valid SystemTime while preserving
the raw secs value for round-trip encoding correctness.

Fixes: RustCrypto#503
@tarcieri tarcieri changed the title ssh-key: accept u64::MAX as OpenSSH "no expiry" sentinel in UnixTime ssh-key: allow u64::MAX as "no expiry" sentinel in UnixTime May 10, 2026
#[cfg(not(feature = "std"))]
pub fn new(secs: u64) -> Result<Self> {
if secs <= MAX_SECS {
if secs == FOREVER_SECS || secs <= MAX_SECS {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Seems like the FOREVER_SECS case could use a convenience constructor like pub fn new_non_expiring or something to that effect, but that can be added as a followup

@tarcieri
tarcieri merged commit 51bd0aa into RustCrypto:master May 10, 2026
14 checks passed
@wiktor-k

wiktor-k commented May 20, 2026

Copy link
Copy Markdown
Contributor

This bug was recently reported by a user of ssh-agent-lib: wiktor-k/ssh-agent-lib#101 (comment)

ssh-key accumulated quite a few important fixes at this point. I'm afraid to do that 😬 but here it goes: is there a new release planned in the near future? 😅

Edit: FTR the release question is discussed here: #475

@tarcieri

Copy link
Copy Markdown
Member

Yep, #475 is the place to ask

sini added a commit to sini/ssh-agent-mux that referenced this pull request Aug 14, 2026
 overhacked#56)

ssh-agent-lib 0.5.1 typed identities as ssh_key::public::KeyData, which cannot
represent an OpenSSH certificate: request_identities decoded a
...-cert-v01@openssh.com blob into a lossy opaque key and re-serialized a
truncated identity, so any upstream agent holding a certificate made
`ssh-add -l` fail with "incomplete message" and (with overhacked#94) silently dropped
every other agent's keys.

Bump to ssh-agent-lib 0.6.0, whose PublicCredential (Key | Cert) round-trips
certificates losslessly in both identity listings and sign requests. Key the
known-keys map by credential.key_data() so a certificate, its bare public key,
and the sign request ssh issues all resolve to the same upstream agent.

Note: certificates with valid_before = u64::MAX ("Valid: forever") still fail
to decode under the ssh-key 0.6.7 that ssh-agent-lib 0.6.0 builds on
(RustCrypto/SSH#504, fixed in ssh-key 0.7). Certificates with a real
expiration -- as OpenSSH and correctly configured issuers produce -- work now.
sini added a commit to sini/ssh-agent-mux that referenced this pull request Aug 14, 2026
 overhacked#56)

ssh-agent-lib 0.5.1 typed identities as ssh_key::public::KeyData, which cannot
represent an OpenSSH certificate: request_identities decoded a
...-cert-v01@openssh.com blob into a lossy opaque key and re-serialized a
truncated identity, so any upstream agent holding a certificate made
`ssh-add -l` fail with "incomplete message" and (with overhacked#94) silently dropped
every other agent's keys.

Bump to ssh-agent-lib 0.6.0, whose PublicCredential (Key | Cert) round-trips
certificates losslessly in both identity listings and sign requests. Key the
known-keys map by credential.key_data() so a certificate, its bare public key,
and the sign request ssh issues all resolve to the same upstream agent.

Note: certificates with valid_before = u64::MAX ("Valid: forever") still fail
to decode under the ssh-key 0.6.7 that ssh-agent-lib 0.6.0 builds on
(RustCrypto/SSH#504, fixed in ssh-key 0.7). Certificates with a real
expiration -- as OpenSSH and correctly configured issuers produce -- work now.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

certificates with infinite validity fail to parse

3 participants