using System; using System.Security.Cryptography; using System.Text; using Paca.Core.Security; using Xunit; namespace Paca.Tests.Security; public class VirtualFido2AuthenticatorTests { [Fact] public void MakeCredential_Generates_Valid_Key_And_CredentialId() { var auth = new VirtualFido2Authenticator(); var cred = auth.CreateCredential("paca.app", "user-123", "PacaTester"); Assert.NotNull(cred); Assert.False(string.IsNullOrWhiteSpace(cred.CredentialId)); Assert.NotNull(cred.PublicKeyBytes); Assert.True(cred.PublicKeyBytes.Length > 0); Assert.Equal("paca.app", cred.RpId); } [Fact] public void GetAssertion_Produces_Verifiable_Signature() { var auth = new VirtualFido2Authenticator(); var cred = auth.CreateCredential("login.chanpaca.net", "user-456", "Alice"); byte[] clientDataHash = SHA256.HashData(Encoding.UTF8.GetBytes("{\"challenge\":\"random-nonce-12345\"}")); var assertion = auth.SignChallenge(cred.CredentialId, clientDataHash); Assert.NotNull(assertion); Assert.Equal(cred.CredentialId, assertion.CredentialId); Assert.NotNull(assertion.Signature); Assert.NotNull(assertion.AuthenticatorData); // 검증 성공 확인 bool isValid = auth.VerifyAssertion(cred.CredentialId, clientDataHash, assertion.AuthenticatorData, assertion.Signature); Assert.True(isValid, "유효한 FIDO2 어설션 서명은 검증에 통과해야 합니다."); } [Fact] public void VerifyAssertion_Fails_When_Data_Tampered() { var auth = new VirtualFido2Authenticator(); var cred = auth.CreateCredential("login.chanpaca.net", "user-789", "Bob"); byte[] clientDataHash = SHA256.HashData(Encoding.UTF8.GetBytes("original challenge")); var assertion = auth.SignChallenge(cred.CredentialId, clientDataHash); byte[] tamperedHash = SHA256.HashData(Encoding.UTF8.GetBytes("tampered challenge")); bool isValid = auth.VerifyAssertion(cred.CredentialId, tamperedHash, assertion.AuthenticatorData, assertion.Signature); Assert.False(isValid, "변조된 clientDataHash에 대한 서명 검증은 반드시 실패해야 합니다."); } [Fact] public void NonExistentCredential_Throws_Or_Returns_Null() { var auth = new VirtualFido2Authenticator(); byte[] dummyHash = new byte[32]; Assert.Throws(() => { auth.SignChallenge("non-existent-cred-id", dummyHash); }); } }