You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 07:18:11