ddn.net.ssh.keys

SSH public key and signature codecs (RFC 4253 section 6.6, RFC 8332).

Parses and encodes the key blob formats used by the initial profile (ssh-ed25519, ssh-rsa), parses signature blobs, separates the RSA key-format name from the SHA-2 signature algorithm names, and bridges parsed keys to the ddn-crypto verifiers. OpenSSH public-key lines and SHA-256 fingerprints round out the trust-facing surface.

The SHA-1 based ssh-rsa signature algorithm is never accepted: parsing succeeds (peers may offer it), but verification rejects it with a typed error, keeping the no-SHA-1-signature policy of the initial profile in one place.

Types 5

classSshKeyException : Exception

Raised for malformed, unsupported, or policy-rejected key or signature material.

Constructors
this(string msg, string file = __FILE__, size_t line = __LINE__)Constructs a key-codec exception.

Key-codec limits from the support matrix.

blobMax = 65536Maximum public key blob size in bytes
rsaMinBits = 2048Minimum accepted RSA modulus size in bits

A parsed SSH public key.

Field data are slices into the parsed blob; keep the blob alive as long as the struct is used. rawBlob preserves the exact received bytes for fingerprinting and transcript hashing.

Fields
string keyAlgorithmKey-format name, for example ssh-ed25519 or ssh-rsa
const(ubyte)[] ed25519KeyEd25519 public key bytes (valid for ssh-ed25519)
const(ubyte)[] rsaERSA public exponent magnitude (valid for ssh-rsa)
const(ubyte)[] rsaNRSA modulus magnitude (valid for ssh-rsa)
string ecdsaCurveECDSA curve identifier (valid for ecdsa-sha2-nistp256)
const(ubyte)[] ecdsaPointSEC 1 uncompressed point (valid for ecdsa-sha2-nistp256)
string commentComment from a public-key line, empty when absent
const(ubyte)[] rawBlobThe complete blob the key was parsed from

A parsed SSH signature blob.

Fields
string signatureAlgorithmSignature algorithm name, for example rsa-sha2-256
const(ubyte)[] signatureAlgorithm-specific signature body

Verifies SSH signatures against a parsed public key using the ddn-crypto primitives.

Fields
private SshParsedPublicKey key_
Methods
SshPublicKeyVerifier create(SshParsedPublicKey key) static @safeCreates a verifier for a parsed key.
bool verify(const(ubyte)[] signedData, scope const SshParsedSignature signature)Verifies a signature over the given data.
Constructors

Functions 21

fnSshParsedPublicKey parseSshPublicKeyBlob(const(ubyte)[] blob) @safeParses a public key blob (the string payload of a key exchange or the base64 body of a public-key line).
private fnSshParsedPublicKey parseSshPublicKeyBlobChecked(const(ubyte)[] blob) @safe
fnbool isParsedSshPublicKeyAlgorithm(string algorithm) @safe pure nothrowWhether a public key blob advertising this algorithm name can be structurally parsed by parseSshPublicKeyBlob.
fnubyte[] buildSshEd25519PublicKeyBlob(const(ubyte)[] keyBytes) @safeBuilds a wire-encoded ssh-ed25519 public key blob.
fnubyte[] buildSshRsaPublicKeyBlob(const(ubyte)[] e, const(ubyte)[] n) @safeBuilds a wire-encoded ssh-rsa public key blob from magnitude bytes.
fnubyte[] buildSshEcdsaP256PublicKeyBlob( const(ubyte)[] uncompressedPoint) @safeBuilds a wire-encoded ecdsa-sha2-nistp256 public key blob.
fnubyte[] sshEcdsaP256SignatureBodyFromRaw( const(ubyte)[] rawSignature) @safeConverts a fixed-width P-256 signature to the SSH ECDSA body.
fnubyte[] sshEcdsaP256SignatureBodyToRaw( const(ubyte)[] signatureBody) @safeConverts an SSH ECDSA body to fixed-width primitive form.
fnSshParsedSignature parseSshSignatureBlob(const(ubyte)[] blob) @safeParses a signature blob into its algorithm name and raw signature.
private fnSshParsedSignature parseSshSignatureBlobChecked(const(ubyte)[] blob) @safe
fnubyte[] buildSshSignatureBlob(string algorithm, const(ubyte)[] signature) @safeBuilds a wire-encoded signature blob.
fnbool isSupportedSignatureAlgorithm(string algorithm) @safe pure nothrowChecks whether a signature algorithm is accepted by the initial profile policy.
fnstring sshKeyFingerprintSha256(const(ubyte)[] blob)Computes the unpadded base64 SHA-256 fingerprint of a key blob.
fnstring formatSshFingerprint(const(ubyte)[] blob)Formats a fingerprint the way OpenSSH tools display it.
fnSshParsedPublicKey parseOpenSSHPublicKeyLine(string line, size_t maxLine = 16384) @safeParses an OpenSSH public-key line: algorithm, base64 blob, optional comment.
private fnBigInt magnitudeToBigInt(const(ubyte)[] bytes) @safe pureConverts a big-endian magnitude to a BigInt.
private fnbool validP256Point(const(ubyte)[] point) @trusted
private fnbool validP256Scalar(const(ubyte)[] magnitude) @trusted
private fnubyte[] base64DecodeNoPad(string text) @trustedDecodes base64 with or without padding, bounded by the input length.
private fnsize_t indexOf(string haystack, string needle) @safe pure nothrow
private fnimmutable(ubyte)[] hexBytes(string hex) @safeDecodes hexadecimal fixture text into bytes for the test data above.

Variables 8

private varubyte[] ed25519FixtureBlob = hexBytes( "0000000b7373682d65643235353139000000207dab75e8d6db8ecf05f7954bc7a59ad5f345371a01ea807dff7af171e091a8be")

Independent fixtures: python-built blobs from OpenSSL keys.

private varubyte[] ed25519FixtureSignature = hexBytes( "0000000b7373682d656432353531390000004027c2d5c89addbd44172e2f8974dc63b57da65371c8e5e9451ca2e5f0b3dd7f95e62603e5b8d992f8b643ec98a7f244bcb51f46579ba121441a8dd4fd399c040e")
private varubyte[] rsaFixtureBlob = hexBytes( "000000077373682d727361000000030100010000010100bbac7dea825d77ea3485471ae15a9ca6cfc1abec3a849ca63457348e62b399c3623d31609dfbde835c7ed0ac597a9d012291775f9f82d5c004b07d0a8d88792ba0496a17682584898154c725aec717708737f1d0b75336c9673879d2cb84994f0f26082f7539d5bf66cd3ddb0932a48f8c9985368653ce8e55e4c770a9e2ac73363cceb4dbe9abe383993b1eb53ab462ebb7e1e461a016f5a73020c8331b96b62588014ea1663f1e3190fc9bada87cbfd98e0af52776c70ca852cb17b46ca3ef6d3ccba3ab0fbe7c66bbaddc0613ebb0655f1b5b8d069ed691533a786b054e76143ea03b49baaafd8eea0cf0ae94401b69e5f7fadbca88993d1ca6c81ee252f3")
private varubyte[] rsaFixtureSignature = hexBytes( "0000000c7273612d736861322d3235360000010027effa34dc0036d727ab63c40dc3028cfcecce36ee29892e778ccb29b6bee95cc04a359ddf28acb6657978152c97a23833c1eee79d51a5380f1f8687cfb78261fcf7de53780faaa0f3b6931307733fa4b8c51d375a21620092bff3b678cf4ceb8fdb4ce6e5ac06508eac25fb9381b396beedeedd3a97f33a17adf67cba435afbbb98747ef7893404c4b029735a6a8ae5e29fff3ab053c5cf0fa9099008d9b14025df1783b09281f3a6e99308edb5a1f1c2c8a3c9c879ccbc86defd0084b062dcbdbd98d41c51c40fc3f6e42a4f04471f7da9917c0bc528b197dbb43798d54067616a82f4038db4effb6ff593c42976f4f38e2f26c726f6bdbd07cd6b85f9f2e3")
private varstring fixtureMessage = "DDN SSH profile signature verification vector"
private varubyte[] ecdsaFixturePoint = hexBytes( "0460fed4ba255a9d31c961eb74c6356d68c049b8923b61fa6ce669622e60f29fb6" ~ "7903fe1008b8bc99a41ae9e95628bc64f2f1b20c2d7e9f5177a3c294d4462299")
private varubyte[] ecdsaFixtureSignatureBody = hexBytes( "000000202ae0ce60782d8303271ab4b612a13cdc7cf2714ffe9ed5377eb913a33b79b725" ~ "0000002100ceeaacd8c1005a6a8e6d3516c05c405f7e60b7aa4d74906bf544b7aefd1ea3b2")
private varubyte[] ecdsaFixtureMessage = hexBytes( "73616d706c65206d65737361676520666f72207373682065636473612066697874757265")