// // Srp6aExchangeTests.swift // PortalKitTests // // Verification of 2048-bit SRP-6a end-to-end key exchange with mock server parameters. // import XCTest @testable import PortalKit final class Srp6aExchangeTests: XCTestCase { func testEndToEndExchangeSuccess() throws { let pin = "654321" let mockCertHash = SrpGroup.rfc5054_2048.hashAlgorithm.hash("MOCK_CERT_LEAF_DER".data(using: .utf8)!) let server = SrpServerMock(pin: pin) let client = PortalSrpClient() // Client computes M1 bound to mock TLS cert hash let clientM1Hex = try client.computeM1( saltHex: server.saltHex, pubBHex: server.pubBHex, pin: pin, tlsCertSha256: mockCertHash ) XCTAssertFalse(clientM1Hex.isEmpty) XCTAssertNotNil(client.sessionKey) // Server verifies client's A and M1 let verifyResult = server.verifyClient( pubAHex: client.pubAHex, clientM1Hex: clientM1Hex, serverTlsCertSha256: mockCertHash ) XCTAssertTrue(verifyResult.success, "Server rejected valid client proof") XCTAssertNotNil(verifyResult.M2Hex) XCTAssertNotNil(verifyResult.token) // Client verifies server M2 XCTAssertNoThrow( try client.verifyServerM2(serverM2Hex: verifyResult.M2Hex!), "Client failed to verify genuine server M2" ) } func testWrongPinFailsExchange() throws { let actualPin = "123456" let wrongPin = "999999" let mockCertHash = Data(repeating: 0x42, count: 32) let server = SrpServerMock(pin: actualPin) let client = PortalSrpClient() // Client computes M1 with wrong PIN let clientM1Hex = try client.computeM1( saltHex: server.saltHex, pubBHex: server.pubBHex, pin: wrongPin, tlsCertSha256: mockCertHash ) // Server verification MUST fail let verifyResult = server.verifyClient( pubAHex: client.pubAHex, clientM1Hex: clientM1Hex, serverTlsCertSha256: mockCertHash ) XCTAssertFalse(verifyResult.success) XCTAssertNil(verifyResult.token) XCTAssertNil(verifyResult.M2Hex) XCTAssertTrue(verifyResult.errorMessage?.contains("M1 verification failed") ?? false) } func testMultipleRandomExchanges() throws { // Run 5 randomized rounds to verify no modular arithmetic edge cases for round in 1...5 { let pin = String(format: "%06d", round * 111111 % 1000000) let mockCertHash = SrpGroup.rfc5054_2048.hashAlgorithm.hash("CERT_ROUND_\(round)".data(using: .utf8)!) let server = SrpServerMock(pin: pin) let client = PortalSrpClient() let m1Hex = try client.computeM1( saltHex: server.saltHex, pubBHex: server.pubBHex, pin: pin, tlsCertSha256: mockCertHash ) let serverRes = server.verifyClient( pubAHex: client.pubAHex, clientM1Hex: m1Hex, serverTlsCertSha256: mockCertHash ) XCTAssertTrue(serverRes.success, "Round \(round) failed server verification") guard let m2 = serverRes.M2Hex else { XCTFail("Round \(round) missing M2") continue } XCTAssertNoThrow(try client.verifyServerM2(serverM2Hex: m2), "Round \(round) failed client M2 verification") } } }