Swift使用证书身份发起HTTPS请求时出现EXC_BAD_ACCESS错误求助
iOS Swift 使用SecIdentity发起HTTPS请求时EXC_BAD_ACCESS崩溃排查
我是Swift新手,尝试通过证书和密钥创建SecIdentity发起HTTPS请求时,触发了EXC_BAD_ACCESS (code=2, address=0x2f30650004)错误。代码在创建URLSession(let session = URLSession(configuration: .default, delegate: URLSessionPinningDelegate(identity: identity), delegateQueue: nil))及调用dataTask时崩溃。移除身份使用默认URLSession时,请求返回401但不会崩溃,推测错误和URLSession及身份配置相关。
创建SecIdentity的代码
func loadIdentity(certificate: String, privateKey: String)-> SecIdentity? { guard let certData = Data(base64Encoded: certificate, options:NSData.Base64DecodingOptions.ignoreUnknownCharacters) else { print("Unable to decode certificate PEM") return nil } guard let cert = SecCertificateCreateWithData(kCFAllocatorDefault, certData as CFData) else { return nil } let addCertQuery: [String: Any] = [ kSecClass as String: kSecClassCertificate, kSecValueRef as String: cert, kSecAttrLabel as String: "certificateLabel" ] let tag = "fedvfdvdf-tag".data(using: .utf8)! _ = deleteCertificateAndKey(certLabel: "certificateLabel",keyTag: tag ) let certAddStatus = SecItemAdd(addCertQuery as CFDictionary, nil) guard let pemKeyData = Data(base64Encoded: privateKey, options:NSData.Base64DecodingOptions.ignoreUnknownCharacters) else { return nil } let sizeInBits = pemKeyData.count * 8 let keyDict: [CFString: Any] = [ kSecAttrKeyType: kSecAttrKeyTypeRSA, kSecAttrKeyClass: kSecAttrKeyClassPrivate, kSecAttrKeySizeInBits: NSNumber(value: sizeInBits), kSecReturnPersistentRef: true ] var error: Unmanaged<CFError>? guard let key = SecKeyCreateWithData(pemKeyData as CFData, keyDict as CFDictionary, &error) else { return nil } let addKeyQuery: [String: Any] = [ kSecClass as String: kSecClassKey, kSecAttrIsPermanent as String: true, kSecValueRef as String: key, kSecAttrApplicationTag as String: tag ] let privKeyAddStatus = SecItemAdd(addKeyQuery as CFDictionary, nil) let getIdentityQuery = [ kSecClass : kSecClassIdentity, kSecReturnData : true, kSecReturnAttributes : true, kSecReturnRef : true, kSecMatchLimit : kSecMatchLimitAll ] as CFDictionary var identityItem: CFTypeRef? let status = SecItemCopyMatching(getIdentityQuery , &identityItem) print("identityItem finished with status: \(String(describing: identityItem))") print("status finished with status: \(status)") guard status == errSecSuccess else { print("Unable to create identity") return nil } return (identityItem as! SecIdentity); }
发起API请求的代码
func makeAzureRequest(scopeId:String, registrationId:String, key:String, certificate:String, provisionHost:String, fileNameWithFolder:String, modelId:String, completion: @escaping (Result<String, Error>) -> Void ) throws { guard let identity = loadIdentity(certificate: certificate, privateKey: key) else { throw NSError(domain: "", code: -1, userInfo: [NSLocalizedDescriptionKey: "Unable to create identity"]) } let session = URLSession(configuration: .default, delegate: URLSessionPinningDelegate(identity: identity), delegateQueue: nil) print("session: \(session)") guard let url = URL(string: "https://global.azure-devices-provisioning.net/\(scopeId)/registrations/\(registrationId)/register?api-version=2021-06-01") else { throw NSError(domain: "", code: -1, userInfo: [NSLocalizedDescriptionKey: "Invalid URL"]) } var request = URLRequest(url: url) request.httpMethod = "PUT" request.setValue("application/json", forHTTPHeaderField: "Content-Type") request.setValue("utf-8", forHTTPHeaderField: "Content-Encoding") let body = ["registrationId": registrationId] request.httpBody = try? JSONSerialization.data(withJSONObject: body, options: []) let task = session.dataTask(with: request) { (data, response, error) in if let error = error { completion(.failure(error)) } else if let data = data, let responseString = String(data: data, encoding: .utf8) { completion(.success(responseString)) }else { completion(.failure(NSError(domain: "", code: -1, userInfo: [NSLocalizedDescriptionKey: "Unknown error occurred"]))) } } task.resume() }
触发请求的调用代码
@objc(AzureProvisionWithCertificate) class AzureProvisionWithCertificate: NSObject { @objc(provisionAndUploadFile:withRegistrationId:withKey:withCertificate:withProvisionHost:withFileNameWithFolder:withModelId:withResolver:withRejecter:) func provisionAndUploadFile(scopeId:String, registrationId:String, key:String, certificate:String, provisionHost:String, fileNameWithFolder:String, modelId:String, resolve:@escaping RCTPromiseResolveBlock, reject:@escaping RCTPromiseRejectBlock) -> Void { print("starting swift code here") do { try makeAzureRequest(scopeId: scopeId, registrationId:registrationId, key: key, certificate: certificate, provisionHost: provisionHost, fileNameWithFolder: fileNameWithFolder, modelId: modelId) { result in switch result { case .success(let responseString): print("Success! Response: \(responseString)") // Handle success, perhaps update the UI or process the response case .failure(let error): print("Failed with error: \(error.localizedDescription)") // Handle failure, perhaps show an error message to the user } } } catch { print("Failed to initiate request: \(error.localizedDescription)") } } }
URLSession代理类代码
import Foundation import Security class URLSessionPinningDelegate: NSObject, URLSessionDelegate { var identity: SecIdentity init(identity: SecIdentity) { self.identity = identity } func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodClientCertificate { let credential = URLCredential(identity: self.identity, certificates: nil, persistence: .forSession) completionHandler(.useCredential, credential) } else { completionHandler(.performDefaultHandling, nil) } } }
崩溃堆栈信息
* frame #0: 0x000000019e78b038 libobjc.A.dylib`objc_msgSend + 56 frame #1: 0x00000001af0be964 Security`SecIdentityCopyCertificate + 24 frame #2: 0x00000001d7e3fd2c libboringssl.dylib`boringssl_identity_create_from_identity + 92 frame #3: 0x00000001d7e50488 libboringssl.dylib`boringssl_context_set_identity + 284 frame #4: 0x00000001d7e500dc libboringssl.dylib`__boringssl_context_certificate_request_callback_block_invoke_3 + 1048 frame #5: 0x00000001a6de6230 Network`nw_queue_context_async_if_needed + 88 frame #6: 0x00000001d7e4fc9c libboringssl.dylib`__boringssl_context_certificate_request_callback_block_invoke_2 + 148 frame #7: 0x00000001a7b43668 CFNetwork`___lldb_unnamed_symbol8855 + 576 frame #8: 0x00000001a7bdab08 CFNetwork`___lldb_unnamed_symbol12666 + 204 frame #9: 0x00000001a7b43b08 CFNetwork`___lldb_unnamed_symbol8863 + 700 frame #10: 0x00000001a7b86738 CFNetwork`___lldb_unnamed_symbol10375 + 84 frame #11: 0x00000001a7b869d0 CFNetwork`___lldb_unnamed_symbol10379 + 36 frame #12: 0x00000001079e0b98 libdispatch.dylib`_dispatch_call_block_and_release + 32 frame #13: 0x00000001079e27bc libdispatch.dylib`_dispatch_client_callout + 20 frame #14: 0x00000001079ea66c libdispatch.dylib`_dispatch_lane_serial_drain + 832 frame #15: 0x00000001079eb43c libdispatch.dylib`_dispatch_lane_invoke + 460 frame #16: 0x00000001079ecabc libdispatch.dylib`_dispatch_workloop_invoke + 2336 frame #17: 0x00000001079f8404 libdispatch.dylib`_dispatch_root_queue_drain_deferred_wlh + 328 frame #18: 0x00000001079f7a38 libdispatch.dylib`_dispatch_workloop_worker_thread + 444 frame #19: 0x0000000203763934 libsystem_pthread.dylib`_pthread_wqthread + 288
恳请各位帮忙排查解决,谢谢!
内容的提问来源于stack exchange,提问作者user26952423
相关产品推荐
相关产品推荐

