Add managed TLS interoperability and persisted credentials
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
using System.Security.Cryptography;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Formats.Asn1;
|
||||
using VoiceCat.Crypto;
|
||||
|
||||
namespace VoiceCat.Tests;
|
||||
|
||||
public class IdentityTests
|
||||
{
|
||||
[Fact]
|
||||
public void CredentialsSurviveRestartAndBindIdentityIntoCertificate()
|
||||
{
|
||||
string directory = Path.Combine(Path.GetTempPath(), "voicecat-credentials-" + Guid.NewGuid());
|
||||
try
|
||||
{
|
||||
string identityFingerprint, certificateFingerprint;
|
||||
using (var credentials = ServerCredentials.LoadOrCreate(directory, "Server, with punctuation"))
|
||||
{
|
||||
identityFingerprint = credentials.Identity.Fingerprint;
|
||||
certificateFingerprint = credentials.CertificateFingerprint;
|
||||
using var tls = credentials.CreateTlsSession();
|
||||
Assert.False(tls.IsReady);
|
||||
byte[] identity = File.ReadAllBytes(Path.Combine(directory, "identity.key"));
|
||||
Assert.Equal(96, identity.Length);
|
||||
Assert.Equal(identity[..32], identity[64..]);
|
||||
using var certificate = X509Certificate2.CreateFromPem(File.ReadAllText(Path.Combine(directory, "server.crt")));
|
||||
var san = new AsnReader(certificate.Extensions["2.5.29.17"]!.RawData, AsnEncodingRules.DER).ReadSequence();
|
||||
Assert.Equal("urn:voicecat:identity:ed25519:" + Convert.ToHexString(credentials.Identity.PublicKey).ToLowerInvariant(),
|
||||
san.ReadCharacterString(UniversalTagNumber.IA5String, new Asn1Tag(TagClass.ContextSpecific, 6)));
|
||||
Assert.False(san.HasData);
|
||||
}
|
||||
using var restored = ServerCredentials.LoadOrCreate(directory, "ignored after creation");
|
||||
Assert.Equal(identityFingerprint, restored.Identity.Fingerprint);
|
||||
Assert.Equal(certificateFingerprint, restored.CertificateFingerprint);
|
||||
File.Delete(Path.Combine(directory, "server.key"));
|
||||
Assert.Throws<InvalidDataException>(() => ServerCredentials.LoadOrCreate(directory, "unchanged"));
|
||||
using var stillPresent = ServerIdentity.Load(Path.Combine(directory, "identity.key"));
|
||||
Assert.Equal(identityFingerprint, stillPresent.Fingerprint);
|
||||
}
|
||||
finally { if (Directory.Exists(directory)) Directory.Delete(directory, true); }
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TofuRequiresExplicitPinAndPreservesCppFileFormat()
|
||||
{
|
||||
string directory = Path.Combine(Path.GetTempPath(), "voicecat-pins-" + Guid.NewGuid());
|
||||
Directory.CreateDirectory(directory);
|
||||
string path = Path.Combine(directory, "pins.txt");
|
||||
string fingerprint = Convert.ToHexString(RandomNumberGenerator.GetBytes(32));
|
||||
try
|
||||
{
|
||||
var store = new TofuStore(path);
|
||||
Assert.Equal(TofuStatus.FirstConnect, store.Check("localhost", 9987, fingerprint));
|
||||
Assert.False(File.Exists(path));
|
||||
store.Pin("localhost", 9987, fingerprint);
|
||||
Assert.Equal($"localhost:9987 {fingerprint.ToLowerInvariant()}\n", File.ReadAllText(path));
|
||||
store = new(path);
|
||||
Assert.Equal(TofuStatus.Matched, store.Check("localhost", 9987, fingerprint));
|
||||
Assert.Equal(TofuStatus.Mismatch, store.Check("localhost", 9987, new string('0', 64)));
|
||||
Assert.Equal(TofuStatus.Matched, new TofuStore(path).Check("localhost", 9987, fingerprint));
|
||||
store.Remove("localhost", 9987);
|
||||
Assert.Equal(TofuStatus.FirstConnect, new TofuStore(path).Check("localhost", 9987, fingerprint));
|
||||
File.WriteAllText(path, "localhost:9987 " + new string('g', 64));
|
||||
Assert.Throws<InvalidDataException>(() => new TofuStore(path));
|
||||
}
|
||||
finally { Directory.Delete(directory, true); }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user