Skip to content

Fix UTF-8 string encoding and harden the certificate builder - #57

Merged
darinkes merged 7 commits into
mainfrom
fix/utf8-string-encoding
Jul 21, 2026
Merged

Fix UTF-8 string encoding and harden the certificate builder#57
darinkes merged 7 commits into
mainfrom
fix/utf8-string-encoding

Conversation

@darinkes

Copy link
Copy Markdown
Owner

Summary

Review fixes for the string-encoding bug and a few smaller hardening items.

  • Encode SSH strings as UTF-8 instead of ASCII (major): EncodeBinary(string) mangled every non-ASCII character to ?. This made PuTTY reject exported .ppk files with a non-ASCII comment ("MAC failed": the Private-MAC was computed over the mangled comment while the file carries UTF-8), minted certificates with corrupted principals/key ids (m?ller instead of müller), corrupted the SSHSIG namespace on both sign and verify (the library could not verify its own output), and corrupted the embedded OpenSSH key comment. UTF-8 is byte-identical for ASCII input, so existing output is unchanged.
  • Leave the caller's stream open in SshKey.Generate(Stream, info): the method disposed the stream it was handed, so callers could not read back what was just written.
  • Validate SshCertificateBuilder input: WithNonce now rejects a null/empty nonce (the spec relies on CA-supplied randomness), WithValidity rejects validAfter > validBefore.
  • Reject non-NIST curves in SshKey.FromKey(ECDsa): curves were mapped purely by key size, so brainpool/secp256k1 keys failed later deep inside SSH.NET with an opaque CryptographicException. The curve OID is now checked and unsupported curves fail fast with a NotSupportedException naming the curve.
  • README: document the .NET key interop (SshKey.FromKey / FromPem / FromEd25519), including that FromPem throws PlatformNotSupportedException on .NET 4.8 / netstandard 2.0.

Each fix comes with a test that fails without it.

Release

Merging this publishes 2024.2.0.4. This should be merged before the SshNet.Agent release PR, whose README references the certificate API.

darinkes added 7 commits July 21, 2026 11:17
ASCII encoding mangled every non-ASCII character to '?': the .ppk
Private-MAC was computed over a mangled comment while the file carries
UTF-8 (PuTTY reports "MAC failed"), certificates were minted with
corrupted principals and key ids, and the SSHSIG namespace was corrupted
on both sign and verify. UTF-8 is byte-identical for ASCII input, so
existing output is unchanged.
Generate(Stream, info) disposed the stream it was handed, so callers
could not read back what was just written.
Reject a null or empty nonce (the spec relies on CA-supplied
randomness) and a validAfter later than validBefore.
The curve was mapped purely by key size, so brainpool or secp256k1
keys were silently treated as NIST curves and failed later inside
SSH.NET with an opaque CryptographicException. Match the curve OID and
fail fast with the curve name instead.
@darinkes
darinkes merged commit a0b20f4 into main Jul 21, 2026
2 checks passed
@darinkes
darinkes deleted the fix/utf8-string-encoding branch July 21, 2026 11:19
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.

1 participant