我的Swift iOS应用程序中有公钥密码代码,效果很好。
我现在正致力于构建单元测试,测试公钥密码,而无需网络连接/实时服务器。我有这个几乎工作,但我无法弄清楚如何以编程方式创建一个具有非零服务器信任的URLAuthenticationChallenge?所有Apple文档都声明,如果您的身份验证方法是NSURLAuthenticationMethodServerTrust,那么这应该是非零的。我正在使用从本地计算机生成的p12和cer文件来构建下面示例中的URLCredential。无论我做什么,challenge.protectionSpace.serverTrust总是回来零。
let protectionSpace = URLProtectionSpace(host: "mockSession",
port: 0,
protocol: "https",
realm: nil,
authenticationMethod: NSURLAuthenticationMethodServerTrust)
var urlCredential:URLCredential?
if let p12Data = try? Data(contentsOf: URL(fileURLWithPath: Bundle.init(for: type(of: self)).path(forResource: "cm7justindomnit", ofType: "p12") ?? "")),
let cerData = try? Data(contentsOf: URL(fileURLWithPath: Bundle.init(for: type(of: self)).path(forResource: "cm7justindomnit", ofType: "cer") ?? "")){
let options: NSDictionary = [kSecImportExportPassphrase:"password"]
var items: CFArray?
let _ = SecPKCS12Import(p12Data as CFData, options, &items)
if let items = items {
let objectsData = Data.init(from: CFArrayGetValueAtIndex(items, 0))
let objects = objectsData.toArray(type: CFDictionary.self).first
let secIdentityData = Data.init(from: CFDictionaryGetValue(objects, Unmanaged.passUnretained(kSecImportItemIdentity).toOpaque()))
if let secIdentity = secIdentityData.toArray(type: SecIdentity.self).first {
if let secCertifiate = SecCertificateCreateWithData(kCFAllocatorDefault, cerData as CFData) {
urlCredential = URLCredential(identity: secIdentity, certificates: [secCertifiate], persistence: .forSession)
}
}
}
}
let challenge = URLAuthenticationChallenge(protectionSpace: protectionSpace,
proposedCredential: urlCredential,
previousFailureCount: 0,
failureResponse: nil,
error: nil,
sender: self)
我有一个数据扩展来处理UnsafeBufferPointers。
extension Data {
init<T>(from value: T) {
var value = value
self.init(buffer: UnsafeBufferPointer(start: &value, count: 1))
}
func to<T>(type: T.Type) -> T {
return self.withUnsafeBytes { $0.pointee }
}
func toArray<T>(type: T.Type) -> [T] {
return self.withUnsafeBytes {
[T](UnsafeBufferPointer(start: $0, count: self.count/MemoryLayout<T>.stride))
}
}
}
答案 0 :(得分:0)
您始终可以将didReceive challenge
- 方法从您正在测试的类中移开,并将其与某些协议通信相关联。然后在需要时调用它的方法。例如:
protocol CheckerProtocol {
// or event simplier
func isOkCertificate(_ certificate: ) -> Bool
}
如果您需要使用证书测试某些逻辑,请直接将其传递给您的检查器依赖项:
if let serverTrust = challenge.protectionSpace.serverTrust {
var secresult = SecTrustResultType(kSecTrustResultInvalid)
let status = SecTrustEvaluate(serverTrust, &secresult)
if status == errSecSuccess {
if let certificate = SecTrustGetCertificateAtIndex(serverTrust, 0) {
if self.checker.isOkCertificate(certificate) { ... }
}
}
}
将检查代码移至
class Checker: CheckerProtocol { ... }
在你的测试目标中:
let certificate = // init right/wrong one
let checker = Checker()
XCTAssert[True|False](checker.isOkCertificate(certificate))
答案 1 :(得分:0)
我意识到这是一个比较老的问题,但是今天在为SSL固定代码编写测试时遇到了同样的问题。我通过子类化URLProtectionSpace
private class TestURLProtectionSpace: URLProtectionSpace {
var internalServerTrust: SecTrust?
override var serverTrust: SecTrust? {
return internalServerTrust
}
}
let protectionSpace = TestURLProtectionSpace(
host: "myhost.com",
port: 443,
protocol: "https",
realm: nil,
authenticationMethod: NSURLAuthenticationMethodServerTrust
)
protectionSpace.internalServerTrust = serverTrust