import Foundation import Security // B4 · Two real, DER-decodable leaf certificates for the enrolled-identity // persistence tests, plus the cleanup they need. // // Both carry the SAME public key (the `KnownGoodCSR` fixed key) and the SAME // subject, and differ only in serial + validity — exactly the shape of a // rotation: `SecItemAdd` treats them as two distinct items, while re-adding one // of them byte-for-byte is `errSecDuplicateItem`. // // CLEANUP, and why it needs its own path: on macOS the file-based keychain // OVERRIDES the `kSecAttrLabel` supplied at add time with the certificate's own // subject summary (verified 2026-07-30: added under // `…test-XYZ.device-leaf`, found only under `enrolled-device-fixture`). So the // production `KeychainClientIdentityStore` label-keyed delete cannot remove them // on macOS, and the tests must sweep by subject instead — `purgeFixtureLeaves()` // runs both BEFORE (in case a previous run was killed) and AFTER every test that // installs one. `SecItemDelete` removes ONE match per call here, hence the loop. // // Regenerated with (OpenSSL 3.0.18, key = KnownGoodCSR.privateKeyX963Base64): // openssl req -x509 -new -key fixed.key.pem -subj "/CN=enrolled-device-fixture" \ // -days 3650 -sha256 -outform DER -out leaf1.der # then -days 3651 → leaf2 // openssl req -x509 -new -key chain.key.pem \ // -subj "/CN=webterm-enrollment-ca-fixture" -days 3650 -sha256 -outform DER enum EnrolledLeafFixtures { /// The subject summary macOS files these certificates under. static let subjectSummary = "enrolled-device-fixture" static var leaf: Data { der(leafBase64) } /// A second, DISTINCT leaf (different serial) for the rotation case. static var rotatedLeaf: Data { der(rotatedLeafBase64) } /// An issuer certificate for the stored `caChain`. static var issuer: Data { der(issuerBase64) } private static func der(_ base64: String) -> Data { Data(base64Encoded: base64, options: .ignoreUnknownCharacters)! } private static let leafBase64 = """ MIIBmTCCAT+gAwIBAgIUcHFyXdi5QFelGKhdzcsbFlgnYzUwCgYIKoZIzj0EAwIwIjEgMB4GA1UE\ AwwXZW5yb2xsZWQtZGV2aWNlLWZpeHR1cmUwHhcNMjYwNzMwMDc1NTAxWhcNMzYwNzI3MDc1NTAx\ WjAiMSAwHgYDVQQDDBdlbnJvbGxlZC1kZXZpY2UtZml4dHVyZTBZMBMGByqGSM49AgEGCCqGSM49\ AwEHA0IABGInyJAZfMKCGjVNFg801yeq2Ar+auw1/4IC+g9tIf7Xa/VDY59VGBU9Vh5LYA7fLzs5\ 6X1TF7ZCweW4mcaiJ9KjUzBRMB0GA1UdDgQWBBRAua2aufygDDq2CJTBF31OG7cNSDAfBgNVHSME\ GDAWgBRAua2aufygDDq2CJTBF31OG7cNSDAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA0gA\ MEUCIQCoLSypPlXvtMsQRMpztt/RpbYKc6iTmBLypqOZc0MxTAIgF/MVWpaLLYVCmcKBPxf7y9yQ\ NX3c6BrYB/fi/WzJsmA= """ private static let rotatedLeafBase64 = """ MIIBmTCCAT+gAwIBAgIUarD2zMEMcxZJNQevMMJenCAlLpkwCgYIKoZIzj0EAwIwIjEgMB4GA1UE\ AwwXZW5yb2xsZWQtZGV2aWNlLWZpeHR1cmUwHhcNMjYwNzMwMDc1NTAyWhcNMzYwNzI4MDc1NTAy\ WjAiMSAwHgYDVQQDDBdlbnJvbGxlZC1kZXZpY2UtZml4dHVyZTBZMBMGByqGSM49AgEGCCqGSM49\ AwEHA0IABGInyJAZfMKCGjVNFg801yeq2Ar+auw1/4IC+g9tIf7Xa/VDY59VGBU9Vh5LYA7fLzs5\ 6X1TF7ZCweW4mcaiJ9KjUzBRMB0GA1UdDgQWBBRAua2aufygDDq2CJTBF31OG7cNSDAfBgNVHSME\ GDAWgBRAua2aufygDDq2CJTBF31OG7cNSDAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA0gA\ MEUCID2FFmKH2+qHB8sICyDuxQPtyj/wOLE24t4ghBEitLRvAiEAnTQQ2FP8Wei+8ITL/K57UP2Z\ YtYbEokKkBCj2bMr3vk= """ private static let issuerBase64 = """ MIIBpTCCAUugAwIBAgIUIkl7VDf6o9lBxtWxh7zFxPYTpo8wCgYIKoZIzj0EAwIwKDEmMCQGA1UE\ Awwdd2VidGVybS1lbnJvbGxtZW50LWNhLWZpeHR1cmUwHhcNMjYwNzMwMDc1NTAyWhcNMzYwNzI3\ MDc1NTAyWjAoMSYwJAYDVQQDDB13ZWJ0ZXJtLWVucm9sbG1lbnQtY2EtZml4dHVyZTBZMBMGByqG\ SM49AgEGCCqGSM49AwEHA0IABM4iWgauVe86+SKZg+jlHkh8VbVf70pgMdGOcpJW+xWb5oqfzxY3\ fW6pIdn3SCo9PG7X22qGtq/PLgpv97wtJvajUzBRMB0GA1UdDgQWBBTT9mdiVZTWcatuYz3NkxCb\ DxDSAjAfBgNVHSMEGDAWgBTT9mdiVZTWcatuYz3NkxCbDxDSAjAPBgNVHRMBAf8EBTADAQH/MAoG\ CCqGSM49BAMCA0gAMEUCIQCxfF8zyRHMW7nSmieDoBxIsOXkMFVPko86THW3TbwrUwIgMZlBP5rz\ FT4Y/G2oA+87xceEDjCrA7FnRZrCrZ4AADk= """ private static func labelQuery() -> [String: Any] { [ kSecClass as String: kSecClassCertificate, kSecAttrLabel as String: subjectSummary, ] } /// How many fixture leaves are currently installed. static func installedCount() -> Int { var query = labelQuery() query[kSecReturnRef as String] = true query[kSecMatchLimit as String] = kSecMatchLimitAll var result: CFTypeRef? guard SecItemCopyMatching(query as CFDictionary, &result) == errSecSuccess else { return 0 } if let array = result as? [Any] { return array.count } return result == nil ? 0 : 1 } /// Remove every installed fixture leaf. Idempotent; safe to call when none /// are installed. static func purgeFixtureLeaves() { var guardCounter = 0 let maxSweeps = 16 // a leaf per enroll in a test; never unbounded while SecItemDelete(labelQuery() as CFDictionary) == errSecSuccess, guardCounter < maxSweeps { guardCounter += 1 } } }