Files

109 lines
3.5 KiB
Swift
Raw Permalink Normal View History

2026-09-13 12:15:36 -07:00
//
// 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")
}
}
}