ServerCertificate.cs
1 namespace GUNRPG.Security; 2 3 public sealed class ServerCertificate 4 { 5 private readonly byte[] _publicKey; 6 private readonly byte[] _signature; 7 8 public ServerCertificate( 9 Guid serverId, 10 byte[] publicKey, 11 DateTimeOffset issuedAt, 12 DateTimeOffset validUntil, 13 byte[] signature) 14 { 15 if (validUntil <= issuedAt) 16 { 17 throw new ArgumentOutOfRangeException(nameof(validUntil), "Certificate expiry must be after issuance."); 18 } 19 20 ServerId = serverId; 21 _publicKey = AuthorityCrypto.CloneAndValidatePublicKey(publicKey); 22 IssuedAt = issuedAt; 23 ValidUntil = validUntil; 24 _signature = AuthorityCrypto.CloneAndValidateSignature(signature); 25 } 26 27 public Guid ServerId { get; } 28 29 public byte[] PublicKey => (byte[])_publicKey.Clone(); 30 31 internal byte[] PublicKeyBytes => _publicKey; 32 33 public DateTimeOffset IssuedAt { get; } 34 35 public DateTimeOffset ValidUntil { get; } 36 37 public byte[] Signature => (byte[])_signature.Clone(); 38 39 internal byte[] SignatureBytes => _signature; 40 41 internal byte[] ComputePayloadHash() => 42 AuthorityCrypto.ComputeCertificatePayloadHash(ServerId, _publicKey, IssuedAt, ValidUntil); 43 44 internal static ServerCertificate Create( 45 Guid serverId, 46 byte[] publicKey, 47 DateTimeOffset issuedAt, 48 DateTimeOffset validUntil, 49 byte[] rootPrivateKey) 50 { 51 var payloadHash = AuthorityCrypto.ComputeCertificatePayloadHash(serverId, publicKey, issuedAt, validUntil); 52 var signature = AuthorityCrypto.SignHashedPayload(rootPrivateKey, payloadHash); 53 return new ServerCertificate(serverId, publicKey, issuedAt, validUntil, signature); 54 } 55 }