HTTPS证书校验报错:无法将SecCertificate转为指定指针类型
Hey there! Let's tackle that frustrating type conversion error you're hitting when trying to validate SSL certificates in your URLSessionDelegate code. The error Cannot convert value of type 'SecCertificate' to expected argument type 'UnsafeMutablePointer<UnsafeRawPointer?>!' comes down to a mismatch in how you're creating the CFArray for your local certificate.
The Root Cause
The error occurs at this line in your code:
let certArrayRef = CFArrayCreate(nil, cert, 1, nil)
CFArrayCreate expects its second parameter to be an array of pointers (UnsafeMutablePointer<UnsafeRawPointer?>), but you're directly passing a SecCertificate instance. Core Foundation APIs require this low-level pointer handling when creating arrays, so we need to adjust how we pass the certificate to the array.
Corrected Full Code
Here's the updated URLSessionDelegate method with fixes applied, plus some safety improvements to avoid crashes from forced unwrapping:
func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust { guard let serverTrust = challenge.protectionSpace.serverTrust, let certificate = SecTrustGetCertificateAtIndex(serverTrust, 0), let cerPath = Bundle.main.path(forResource: "xxxxx", ofType: "der"), let localCertificateData = NSData(contentsOfFile: cerPath) as Data? else { completionHandler(.cancelAuthenticationChallenge, nil) return } // Compare remote and local certificate data let remoteCertificateData = SecCertificateCopyData(certificate) as Data let result = remoteCertificateData == localCertificateData print("Certificate match result: \(result)") // Create local certificate reference correctly let certDataRef = localCertificateData as CFData guard let cert = SecCertificateCreateWithData(nil, certDataRef) else { completionHandler(.cancelAuthenticationChallenge, nil) return } // Wrap certificate in a pointer array for CFArrayCreate let certPointer = Unmanaged.passUnretained(cert).toOpaque() let certArray = [certPointer] as [UnsafeRawPointer] let certArrayRef = CFArrayCreate(nil, certArray, certArray.count, nil) // Configure trust settings SecTrustSetAnchorCertificates(serverTrust, certArrayRef) SecTrustSetAnchorCertificatesOnly(serverTrust, false) // Evaluate trust var trustResult: SecTrustResultType = .invalid SecTrustEvaluate(serverTrust, &trustResult) if trustResult == .unspecified || trustResult == .proceed { let credential = URLCredential(trust: serverTrust) challenge.sender?.use(credential, for: challenge) completionHandler(.useCredential, credential) } else { completionHandler(.cancelAuthenticationChallenge, nil) } } else if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodClientCertificate { guard let path = Bundle.main.path(forResource: "client", ofType: "p12"), let PKCS12Data = NSData(contentsOfFile: path) as Data? else { completionHandler(.cancelAuthenticationChallenge, nil) return } let identityAndTrust = self.extractIdentity(certData: PKCS12Data) let urlCredential = URLCredential( identity: identityAndTrust.identityRef, certificates: identityAndTrust.certArray as? [AnyObject], persistence: .forSession ) completionHandler(.useCredential, urlCredential) } else { completionHandler(.cancelAuthenticationChallenge, nil) } }
Key Changes Explained
- Fixed CFArray Creation: We convert the
SecCertificateto anUnsafeRawPointerusingUnmanaged.passUnretained(cert).toOpaque(), then wrap it in an array of pointers thatCFArrayCreateaccepts. - Safety Improvements: Replaced all forced unwraps (
!) withguard letstatements to gracefully handle cases where resources (like the certificate file) can't be loaded, preventing crashes. - Modernized Data Handling: Converted
NSDatato Swift's nativeDatatype where possible for better compatibility with modern Swift code. - Cleaned Up Credential Creation: Removed redundant
URLCredentialinitialization in the completion handler by reusing the already-created credential.
Bonus Tip
Always avoid forced unwrapping in production code—missing files or invalid certificate data can lead to unexpected crashes. The guard let statements in the corrected code ensure your app handles these edge cases gracefully.
内容的提问来源于stack exchange,提问作者Abu Ul Hassan

