<PackageReference Include="SSH.NET" Version="2025.0.0" />

Certificate

public class Certificate
Represents an OpenSSH certificate as described in https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.certkeys.
using Renci.SshNet.Abstractions; using Renci.SshNet.Common; using System; using System.Collections.Generic; namespace Renci.SshNet.Security { public class Certificate { private sealed class CertificateData : SshData { public string Name { get; set; } public byte[] Nonce { get; set; } public Key Key { get; set; } public SshKeyData KeyData { get; set; } public ulong Serial { get; set; } public uint Type { get; set; } public string KeyId { get; set; } public List<string> ValidPrincipals { get; set; } public ulong ValidAfter { get; set; } public ulong ValidBefore { get; set; } public Dictionary<string, string> CriticalOptions { get; set; } public Dictionary<string, string> Extensions { get; set; } public byte[] SignatureKey { get; set; } public long ByteCountBeforeSignature { get; set; } public byte[] Signature { get; set; } protected override void LoadData() { Name = ReadString(null); Nonce = ReadBinary(); Key = ReadPublicKey(out SshKeyData keyData); KeyData = keyData; Serial = ReadUInt64(); Type = ReadUInt32(); KeyId = ReadString(null); ValidPrincipals = ReadValidPrincipals(ReadBinary()); ValidAfter = ReadUInt64(); ValidBefore = ReadUInt64(); CriticalOptions = ReadExtensionPair(ReadBinary()); Extensions = ReadExtensionPair(ReadBinary()); ReadBinary(); SignatureKey = ReadBinary(); ByteCountBeforeSignature = base.DataStream.Position; Signature = ReadBinary(); } private Key ReadPublicKey(out SshKeyData keyData) { switch (Name) { case "ssh-rsa-cert-v01@openssh.com": keyData = new SshKeyData("ssh-rsa", <ReadPublicKey>g__LoadPublicKeys|61_0(2)); return new RsaKey(keyData); case "ecdsa-sha2-nistp256-cert-v01@openssh.com": case "ecdsa-sha2-nistp384-cert-v01@openssh.com": case "ecdsa-sha2-nistp521-cert-v01@openssh.com": keyData = new SshKeyData(Name.Substring(0, 19), <ReadPublicKey>g__LoadPublicKeys|61_0(2)); return new EcdsaKey(keyData); case "ssh-ed25519-cert-v01@openssh.com": keyData = new SshKeyData("ssh-ed25519", <ReadPublicKey>g__LoadPublicKeys|61_0(1)); return new ED25519Key(keyData); default: throw new NotSupportedException("Certificate type '" + Name + "'."); } } private static Dictionary<string, string> ReadExtensionPair(byte[] data) { Dictionary<string, string> dictionary = new Dictionary<string, string>(); using (SshDataStream sshDataStream = new SshDataStream(data)) { while (!sshDataStream.IsEndOfData) { string key = sshDataStream.ReadString(null); string value = sshDataStream.ReadString(null); dictionary.Add(key, value); } return dictionary; } } private static List<string> ReadValidPrincipals(byte[] data) { List<string> list = new List<string>(); using (SshDataStream sshDataStream = new SshDataStream(data)) { while (!sshDataStream.IsEndOfData) { list.Add(sshDataStream.ReadString(null)); } return list; } } protected override void SaveData() { throw new NotImplementedException(); } } public enum CertificateType : uint { User = 1, Host } private readonly CertificateData _data; public string Name => _data.Name; public byte[] Nonce => _data.Nonce; public Key Key => _data.Key; internal SshKeyData KeyData => _data.KeyData; public ulong Serial => _data.Serial; public CertificateType Type => (CertificateType)_data.Type; public string KeyId => _data.KeyId; public IList<string> ValidPrincipals => _data.ValidPrincipals; public ulong ValidAfterUnixSeconds => _data.ValidAfter; public DateTimeOffset ValidAfter => DateTimeOffset.FromUnixTimeSeconds((long)_data.ValidAfter); public ulong ValidBeforeUnixSeconds => _data.ValidBefore; public DateTimeOffset ValidBefore { get { if (_data.ValidBefore != ulong.MaxValue) return DateTimeOffset.FromUnixTimeSeconds((long)_data.ValidBefore); return DateTimeOffset.MaxValue; } } public IDictionary<string, string> CriticalOptions => _data.CriticalOptions; public IDictionary<string, string> Extensions => _data.Extensions; public byte[] CertificateAuthorityKey => _data.SignatureKey; public string CertificateAuthorityKeyFingerPrint => Convert.ToBase64String(CryptoAbstraction.HashSHA256(CertificateAuthorityKey)).TrimEnd('='); public byte[] Signature => _data.Signature; internal byte[] Bytes { get; } internal byte[] BytesForSignature => Bytes.Take((int)_data.ByteCountBeforeSignature); public Certificate(byte[] data) { Bytes = data; _data = new CertificateData(); _data.Load(Bytes); } } }